diff --git a/.gitignore b/.gitignore index dc6c035a1a..ce9b9d5a70 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,10 @@ ext/SGCT .DS_Store *.swp +# generated glsl files +*.gglsl +*.OpenSpaceGenerated.glsl + # CMake stuff CMakeCache.txt CMakeFiles @@ -18,4 +22,3 @@ install_manifest.txt # Doxygen stuff html/ latex/ -Doxyfile diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e2ce9a511..980e2615c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,9 @@ cmake_minimum_required (VERSION 2.8) project (OpenSpace) -SET(CMAKE_EXE_LINKER_FLAGS /NODEFAULTLIB:\"LIBCMTD.lib\") +if (WIN32) + SET(CMAKE_EXE_LINKER_FLAGS /NODEFAULTLIB:\"LIBCMTD.lib\") +endif () set(OPENSPACE_BASE_DIR "${PROJECT_SOURCE_DIR}") set(OPENSPACE_EXT_DIR "${OPENSPACE_BASE_DIR}/ext") @@ -55,6 +57,7 @@ endif () # Ghoul set(GHOUL_ROOT_DIR "${OPENSPACE_EXT_DIR}/ghoul") include_directories("${GHOUL_ROOT_DIR}/include") +set(BOOST_ROOT "${GHOUL_ROOT_DIR}/ext/boost") add_subdirectory(${GHOUL_ROOT_DIR}) set(DEPENDENT_LIBS ${DEPENDENT_LIBS} Ghoul) @@ -72,6 +75,7 @@ set(DEPENDENT_LIBS ${DEPENDENT_LIBS} ${SGCT_LIBRARIES}) # GLM set(GLM_ROOT_DIR "${GHOUL_ROOT_DIR}/ext/glm") find_package(GLM REQUIRED) +add_definitions(-DGLM_SWIZZLE) include_directories(${GLM_INCLUDE_DIRS}) # GLEW @@ -99,7 +103,12 @@ endif(OPENCL_FOUND) # Kameleon option(KAMELEON_LIBRARY_ONLY "Build with Kameleon as library only" ON) -option(BUILD_SHARED_LIBS "Build Shared Libraries" ON) +if(WIN32) + option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF) +else(WIN32) + option(BUILD_SHARED_LIBS "Build Shared Libraries" ON) +endif(WIN32) +option(KAMELEON_USE_HDF5 "Kameleon use HDF5" OFF) set(KAMELEON_ROOT_DIR ${OPENSPACE_EXT_DIR}/kameleon) set(KAMELEON_INCLUDES ${KAMELEON_ROOT_DIR}/src) add_subdirectory(${KAMELEON_ROOT_DIR}) @@ -120,3 +129,5 @@ endif () ######################################################################################### add_subdirectory(src) + +#add_subdirectory(gui) \ No newline at end of file diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000000..df1e74bf65 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,452 @@ +# Doxyfile 1.7.6.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = OpenSpace +PROJECT_NUMBER = +PROJECT_LOGO = +OUTPUT_DIRECTORY = doc/ +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = YES +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = +BUILTIN_STL_SUPPORT = NO + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = YES +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = YES +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = NO +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = YES +SORT_MEMBERS_CTORS_1ST = YES +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = NO +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = NO +SHOW_FILES = NO +SHOW_NAMESPACES = YES +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +QUIET = YES +WARNINGS = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = YES +WARN_FORMAT = "$file:$line: $text" + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +INPUT = src \ + include + +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cpp \ + *.h \ + *.inl + +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = /ext/* bin/* build/* config/* gui/* kernels/* openspace-data/* scripts/* shaders/* +EXCLUDE_SYMBOLS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = doxygen/header.html +HTML_FOOTER = doxygen/footer.html +HTML_STYLESHEET = doxygen/stylesheet.css +#HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 200 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_SECTIONS = NO +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = +DOCSET_BUNDLE_ID = +DOCSET_PUBLISHER_ID = +DOCSET_PUBLISHER_NAME = +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = YES +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 6 +TREEVIEW_WIDTH = 300 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_RELPATH = http://www.mathjax.org/mathjax +MATHJAX_EXTENSIONS = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = YES +SKIP_FUNCTION_MACROS = NO + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/config/sgct/ccmc_lab_all.xml b/config/sgct/ccmc_lab_all.xml new file mode 100644 index 0000000000..9c2fcd4958 --- /dev/null +++ b/config/sgct/ccmc_lab_all.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/sgct/ccmc_lab_work.xml b/config/sgct/ccmc_lab_work.xml new file mode 100644 index 0000000000..0c9f4069b6 --- /dev/null +++ b/config/sgct/ccmc_lab_work.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/sgct/single.xml b/config/sgct/single.xml index 63abb4989c..404e26df2b 100644 --- a/config/sgct/single.xml +++ b/config/sgct/single.xml @@ -1,13 +1,19 @@ - + - + - + + + + - - + + + + + diff --git a/doxygen/footer.html b/doxygen/footer.html new file mode 100644 index 0000000000..c0bcf0c02b --- /dev/null +++ b/doxygen/footer.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/doxygen/header.html b/doxygen/header.html new file mode 100644 index 0000000000..0cd76f23cb --- /dev/null +++ b/doxygen/header.html @@ -0,0 +1,50 @@ + + + + + +$projectname: $title +$title + + +$treeview +$search +$mathjax + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ diff --git a/doxygen/stylesheet.css b/doxygen/stylesheet.css new file mode 100644 index 0000000000..dd13046594 --- /dev/null +++ b/doxygen/stylesheet.css @@ -0,0 +1,951 @@ +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; +} + +/* @group Heading Levels */ + +h1 { + font-size: 150%; +} + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2 { + font-size: 120%; +} + +h3 { + font-size: 100%; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBF3F6; + border: 1px solid #A3C6D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D728C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4683A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CC1D4; + color: #ffffff; + border: 1px double #86B3CA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +.fragment { + font-family: monospace, fixed; + font-size: 105%; +} + +pre.fragment { + border: 1px solid #C4DAE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; +} + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 8px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBF3F6; + font-weight: bold; + border: 1px solid #C4DAE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBF3F6; + border: 1px solid #C4DAE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF4F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3C6D7; +} + +th.dirtab { + background: #EBF3F6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A8AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FBFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #C4DAE5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; +} + +.memTemplParams { + color: #4683A2; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtemplate { + font-size: 80%; + color: #4683A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBF3F6; + border: 1px solid #A3C6D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; +} + +.memname { + white-space: nowrap; + font-weight: bold; + margin-left: 6px; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8C9D9; + border-left: 1px solid #A8C9D9; + border-right: 1px solid #A8C9D9; + padding: 6px 0px 6px 0px; + color: #254555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 8px; + -moz-border-radius-topleft: 8px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 8px; + -webkit-border-top-left-radius: 8px; + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2EDF2; + +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8C9D9; + border-left: 1px solid #A8C9D9; + border-right: 1px solid #A8C9D9; + padding: 2px 5px; + background-color: #FBFCFD; + border-top-width: 0; + /* opera specific markup */ + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 8px; + -moz-border-radius-bottomright: 8px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7FAFB 95%, #EEF4F7); + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7FAFB), to(#EEF4F7)); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} + +.params, .retval, .exception, .tparams { + border-spacing: 6px 2px; +} + +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + + + + +/* @end */ + +/* @group Directory (tree) */ + +/* for the tree view */ + +.ftvtree { + font-family: sans-serif; + margin: 0px; +} + +/* these are for tree view when used as main index */ + +.directory { + font-size: 9pt; + font-weight: bold; + margin: 5px; +} + +.directory h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +/* +The following two styles can be used to replace the root node title +with an image of your choice. Simply uncomment the next two styles, +specify the name of your image and be sure to set 'height' to the +proper pixel height of your image. +*/ + +/* +.directory h3.swap { + height: 61px; + background-repeat: no-repeat; + background-image: url("yourimage.gif"); +} +.directory h3.swap span { + display: none; +} +*/ + +.directory > h3 { + margin-top: 0; +} + +.directory p { + margin: 0px; + white-space: nowrap; +} + +.directory div { + display: none; + margin: 0px; +} + +.directory img { + vertical-align: -30%; +} + +/* these are for tree view when not used as main index */ + +.directory-alt { + font-size: 100%; + font-weight: bold; +} + +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} + +.directory-alt > h3 { + margin-top: 0; +} + +.directory-alt p { + margin: 0px; + white-space: nowrap; +} + +.directory-alt div { + display: none; + margin: 0px; +} + +.directory-alt img { + vertical-align: -30%; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; +} + +address { + font-style: normal; + color: #2A4F61; +} + +table.doxtable { + border-collapse:collapse; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D5468; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #37677F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #A8C9D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8C9D9; + border-bottom: 1px solid #A8C9D9; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8C9D9; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2EDF2; + font-size: 90%; + color: #254555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8C9D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#8AB6CC; + border:solid 1px #C2D9E4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#36657C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#68A1BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#36657C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + margin-left: 5px; + font-size: 8pt; + padding-left: 5px; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FBFC; + margin: 0px; + border-bottom: 1px solid #C4DAE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug +{ + border-left:4px solid; + padding: 0 0 0 6px; +} + +dl.note +{ + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + border-color: #00D000; +} + +dl.deprecated +{ + border-color: #505050; +} + +dl.todo +{ + border-color: #00C0E0; +} + +dl.test +{ + border-color: #3030E0; +} + +dl.bug +{ + border-color: #C08050; +} + +#projectlogo +{ + text-align: center; + vertical-align: center; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5394B4; + background-color: #006599; + +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90BACE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#335F75; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } + pre.fragment + { + overflow: visible; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + } +} + diff --git a/ext/ghoul b/ext/ghoul index 476cf3aece..08152443a9 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 476cf3aeced29deffeb8ba97a5d3d4bfa8750cec +Subproject commit 08152443a9808cf84cf217e252b80d93089ee9b4 diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 7feae25029..e33b8eb266 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -1,8 +1,3 @@ cmake_minimum_required(VERSION 2.8.11) -project(GUI) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GUI_SOURCE_DIR}/build-debug) - -set(CMAKE_BUILD_TYPE Debug) - -add_subdirectory(src) \ No newline at end of file +add_subdirectory(luascriptexternalcontrol) \ No newline at end of file diff --git a/gui/luascriptexternalcontrol/CMakeLists.txt b/gui/luascriptexternalcontrol/CMakeLists.txt new file mode 100644 index 0000000000..b4ff6d4784 --- /dev/null +++ b/gui/luascriptexternalcontrol/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.8.11) + +project(LuascriptExternalControl) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +find_package(Qt5Widgets) +find_package(Qt5Network) +add_executable(LuascriptExternalControl WIN32 main.cpp mainwindow.cpp) +target_link_libraries(LuascriptExternalControl Qt5::Widgets Qt5::Network) \ No newline at end of file diff --git a/gui/luascriptexternalcontrol/main.cpp b/gui/luascriptexternalcontrol/main.cpp new file mode 100644 index 0000000000..59eb5baf55 --- /dev/null +++ b/gui/luascriptexternalcontrol/main.cpp @@ -0,0 +1,35 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include "mainwindow.h" + +int main(int argc, char** argv) { + QApplication app(argc, argv); + + MainWidget window; + window.show(); + + return app.exec(); +} diff --git a/gui/luascriptexternalcontrol/mainwindow.cpp b/gui/luascriptexternalcontrol/mainwindow.cpp new file mode 100644 index 0000000000..31fb8b31da --- /dev/null +++ b/gui/luascriptexternalcontrol/mainwindow.cpp @@ -0,0 +1,103 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "mainwindow.h" + +#include +#include +#include + +MainWidget::MainWidget() + : _ipAddress(new QLineEdit) + , _command(new QLineEdit) + , _logWindow(new QTextEdit) + , _socket(nullptr) +{ + setWindowTitle("OpenSpace LuaScripting GUI"); + + QGridLayout* layout = new QGridLayout; + _ipAddress->setMinimumWidth(200); + _ipAddress->setText("127.0.0.1"); + layout->addWidget(_ipAddress, 0, 0); + + QPushButton* connectButton = new QPushButton("Connect"); + connect(connectButton, SIGNAL(clicked()), this, SLOT(onConnectButton())); + connectButton->show(); + layout->addWidget(connectButton, 0, 1); + + _command->setMinimumWidth(200); + layout->addWidget(_command, 1, 0); + + QPushButton* sendButton = new QPushButton("Send"); + sendButton->setDefault(true); + connect(sendButton, SIGNAL(clicked()), this, SLOT(sendCommandButton())); + layout->addWidget(sendButton, 1, 1); + + layout->addWidget(_logWindow, 2, 0, 1, 2); + + setLayout(layout); +} + +MainWidget::~MainWidget() { + delete _command; + delete _socket; +} + +void MainWidget::readTcpData() { + QByteArray data = _socket->readAll(); + + if (_logWindow->toPlainText().isEmpty()) + _logWindow->setText(data.data()); + else + _logWindow->setText(_logWindow->toPlainText() + "\n" + data.data()); +} + +void MainWidget::onConnectButton() { + delete _socket; + + _socket = new QTcpSocket(this); + connect( _socket, SIGNAL(readyRead()), SLOT(readTcpData()) ); + _socket->connectToHost(_ipAddress->text(), 20500); + +} + +void MainWidget::sendCommandButton() { + if (!_socket) { + if (_logWindow->toPlainText().isEmpty()) + _logWindow->setText("No connection found"); + else + _logWindow->setText(_logWindow->toPlainText() + "\n" + "No connection found"); + return; + } + + QString command = _command->text(); + + if (_logWindow->toPlainText().isEmpty()) + _logWindow->setText(command); + else + _logWindow->setText(_logWindow->toPlainText() + "\n" + command); + + + _socket->write(("0" + command + "\r\n").toLatin1()); +} diff --git a/gui/luascriptexternalcontrol/mainwindow.h b/gui/luascriptexternalcontrol/mainwindow.h new file mode 100644 index 0000000000..46f3a5892d --- /dev/null +++ b/gui/luascriptexternalcontrol/mainwindow.h @@ -0,0 +1,67 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __MAINWINDOW_H__ +#define __MAINWINDOW_H__ + +#include +#include +#include +#include + +class MainWidget : public QWidget { +Q_OBJECT +public: + MainWidget(); + ~MainWidget(); + +private slots: + void onConnectButton(); + void sendCommandButton(); + void readTcpData(); + +private: + QLineEdit* _ipAddress; + QLineEdit* _command; + QTextEdit* _logWindow; + + QTcpSocket* _socket; + + +// +//private slots: +// void on__connectButton_clicked(); +// void on__statsCheckBox_toggled(bool checked); +// void readTcpData(); +// void on__graphCheckBox_toggled(bool checked); +// void on__renderComboBox_currentIndexChanged(const QString &arg1); +// +//private: +// qint64 sendToSGCT(QByteArray data); +// +// Ui::MainWindow *ui; +// QTcpSocket* _sgctSocket; +}; + +#endif // __MAINWINDOW_H__ diff --git a/gui/src/CMakeLists.txt b/gui/src/CMakeLists.txt deleted file mode 100644 index d145273478..0000000000 --- a/gui/src/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# FIXME: ugly hack for linking qt5 -set (CMAKE_PREFIX_PATH "/home/hhellteg/Qt/5.2.1/gcc_64") - -# Find includes in corresponding build directories -set(CMAKE_INCLUDE_CURRENT_DIR ON) -# Instruct CMake to run moc automatically when needed. -set(CMAKE_AUTOMOC ON) - -# Find the Qt libraries -find_package(Qt5Widgets) -find_package(Qt5Network) - -# Create ui_mainwindow.h file -qt5_wrap_ui(QT_UI_HEADERS mainwindow.ui) - -# Tell CMake to create the executable -add_executable(gui main.cpp mainwindow.cpp ${QT_UI_HEADERS}) - -# Use the needed modules from Qt 5. -target_link_libraries(gui Qt5::Widgets Qt5::Network) \ No newline at end of file diff --git a/gui/src/main.cpp b/gui/src/main.cpp deleted file mode 100644 index 1797005f1d..0000000000 --- a/gui/src/main.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "mainwindow.h" -#include -#include - -int main(int argc, char *argv[]) -{ - QApplication a(argc, argv); - MainWindow w; - w.show(); - - return a.exec(); -} diff --git a/gui/src/mainwindow.cpp b/gui/src/mainwindow.cpp deleted file mode 100644 index 39bc8b0eb4..0000000000 --- a/gui/src/mainwindow.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "mainwindow.h" -#include "ui_mainwindow.h" - -#include - -#include -#include -#include -#include - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow), - _sgctSocket(NULL) { - ui->setupUi(this); - ui->_hostEdit->setText("127.0.0.1"); - setWindowTitle("OpenSpace Qt GUI"); - ui->_statsCheckBox->setEnabled(false); - ui->_graphCheckBox->setEnabled(false); - ui->_renderComboBox->setEnabled(false); - -// TEST JSON -// QJsonObject json, jsonObj2; -// QJsonArray jsonArr, jsonArr2; -// json["Value 1"] = (QString("Herp")); -// json["Value 2"] = (QString("Derp")); -// jsonArr.push_back(QString("val1")); -// jsonArr.push_back(QString("val2")); -// jsonArr.push_back(QString("val3")); -// jsonArr.push_back(QString("val4")); -// jsonArr.push_back(QString("val5")); -// jsonArr2.push_back(QString("val21")); -// jsonArr2.push_back(QString("val22")); -// jsonArr2.push_back(QString("val23")); -// jsonArr2.push_back(QString("val24")); -// jsonArr2.push_back(QString("val25")); -// jsonObj2["ArrayYo2"] = jsonArr2; -// jsonArr.push_back(jsonObj2); -// json["ArrayYo"] = jsonArr; -// QJsonDocument doc; -// doc.setObject(json); -// std::cout << doc.toJson().data() << std::endl; -// quick_exit(0); -} - -MainWindow::~MainWindow() { - delete ui; -} - -void MainWindow::on__connectButton_clicked() { - _sgctSocket = new QTcpSocket(this); - connect( _sgctSocket, SIGNAL(readyRead()), SLOT(readTcpData()) ); - _sgctSocket->connectToHost(ui->_hostEdit->text(), 20500); - if (_sgctSocket->waitForConnected()) { - ui->_statsCheckBox->setEnabled(true); - ui->_graphCheckBox->setEnabled(true); - ui->_renderComboBox->setEnabled(true); - } else { - std::cout << "Connection failed" << std::endl; - ui->_statsCheckBox->setEnabled(false); - ui->_graphCheckBox->setEnabled(false); - ui->_renderComboBox->setEnabled(false); - } -} - -void MainWindow::on__statsCheckBox_toggled(bool checked) { - QJsonObject json; - QJsonDocument doc; - if (checked) { - json["stats"] = 1; - } else { - json["stats"] = 0; - } - doc.setObject(json); - std::cout << "Bytes sent: " << sendToSGCT(doc.toJson()) << " " << std::flush; -} - -void MainWindow::on__graphCheckBox_toggled(bool checked) { - QJsonObject json; - QJsonDocument doc; - if (checked) { - json["graph"] = 1; - } else { - json["graph"] = 0; - } - doc.setObject(json); - std::cout << "Bytes sent: " << sendToSGCT(doc.toJson()) << " " << std::flush; -} - -void MainWindow::readTcpData() { - QByteArray data = _sgctSocket->readAll(); - std::cout << data.data() << std::flush; -} - -void MainWindow::on__renderComboBox_currentIndexChanged(const QString &arg1){ - QJsonObject json; - QJsonDocument doc; - if (arg1.compare(QString("VolumeRaycaster")) == 0) { - json["renderer"] = QString("volumeraycaster"); - } else if (arg1.compare(QString("Flare")) == 0) { - json["renderer"] = QString("flare"); - } - doc.setObject(json); - std::cout << "Bytes sent: " << sendToSGCT(doc.toJson()) << " " << std::flush; -} - -qint64 MainWindow::sendToSGCT(QByteArray data) { - return _sgctSocket->write(data + "\r\n"); // "\r\n" seperates messages -} diff --git a/gui/src/mainwindow.h b/gui/src/mainwindow.h deleted file mode 100644 index c392d03b48..0000000000 --- a/gui/src/mainwindow.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include -#include - -namespace Ui { -class MainWindow; -} - -class MainWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); - -private slots: - void on__connectButton_clicked(); - void on__statsCheckBox_toggled(bool checked); - void readTcpData(); - void on__graphCheckBox_toggled(bool checked); - void on__renderComboBox_currentIndexChanged(const QString &arg1); - -private: - qint64 sendToSGCT(QByteArray data); - - Ui::MainWindow *ui; - QTcpSocket* _sgctSocket; -}; - -#endif // MAINWINDOW_H diff --git a/gui/src/mainwindow.ui b/gui/src/mainwindow.ui deleted file mode 100644 index 986a7eb747..0000000000 --- a/gui/src/mainwindow.ui +++ /dev/null @@ -1,102 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 303 - 312 - - - - MainWindow - - - - - - - Graph - - - - - - - - VolumeRaycaster - - - - - Flare - - - - - - - - Connect - - - - - - - Stats - - - - - - - Debug info - - - - - - - Renderer - - - - - - - - - - Host - - - - - - - - - 0 - 0 - 303 - 20 - - - - - - TopToolBarArea - - - false - - - - - - - - diff --git a/include/openspace/abuffer/abuffer.h b/include/openspace/abuffer/abuffer.h new file mode 100644 index 0000000000..f7c2f9e032 --- /dev/null +++ b/include/openspace/abuffer/abuffer.h @@ -0,0 +1,93 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __ABUFFER_H__ +#define __ABUFFER_H__ + +#include + +#include +#include + +#include +#include + +namespace ghoul { + namespace opengl { + class Texture; + } +} + +namespace openspace { + +class ABuffer: public ABuffer_I { +public: + + ABuffer(); + virtual ~ABuffer(); + virtual void resolve(); + + void addVolume(const std::string& tag,ghoul::opengl::Texture* volume); + void addTransferFunction(const std::string& tag,ghoul::opengl::Texture* transferFunction); + int addSamplerfile(const std::string& filename); + +protected: + virtual std::string settings() = 0; + + bool initializeABuffer(); + + void generateShaderSource(); + bool updateShader(); + + std::string openspaceHeaders(); + std::string openspaceSamplerCalls(); + std::string openspaceSamplers(); + std::string openspaceTransferFunction(); + + unsigned int _width, _height, _totalPixels; + +private: + GLuint _screenQuad; + + bool _validShader; + std::string _fragmentShaderPath; + ghoul::filesystem::File* _fragmentShaderFile; + ghoul::opengl::ProgramObject* _resolveShader; + + std::vector > _volumes; + std::vector > _transferFunctions; + std::vector _samplerFiles; + std::vector _samplers; + + // Development functionality to update shader for changes in several files + std::vector _shaderFiles; + + float _volumeStepFactor; + + + +}; // ABuffer +} // openspace + +#endif // __ABUFFER_H__ \ No newline at end of file diff --git a/include/openspace/abuffer/abufferSingleLinked.h b/include/openspace/abuffer/abufferSingleLinked.h new file mode 100644 index 0000000000..c348abee52 --- /dev/null +++ b/include/openspace/abuffer/abufferSingleLinked.h @@ -0,0 +1,60 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __ABUFFERSINGLELINKED_H__ +#define __ABUFFERSINGLELINKED_H__ + +#include + +namespace openspace { + +class ABufferSingleLinked: public ABuffer { +public: + + ABufferSingleLinked(); + virtual ~ABufferSingleLinked(); + virtual bool initialize(); + + virtual void clear(); + virtual void preRender(); + virtual void postRender(); + + virtual std::string settings(); + +private: + + GLuint *_data; + GLuint _anchorPointerTexture; + GLuint _anchorPointerTextureInitializer; + GLuint _atomicCounterBuffer; + GLuint _fragmentBuffer; + GLuint _fragmentTexture; + + + + +}; // ABufferSingleLinked +} // openspace + +#endif // __ABUFFERSINGLELINKED_H__ \ No newline at end of file diff --git a/include/openspace/abuffer/abuffer_i.h b/include/openspace/abuffer/abuffer_i.h new file mode 100644 index 0000000000..04a8e4277c --- /dev/null +++ b/include/openspace/abuffer/abuffer_i.h @@ -0,0 +1,43 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __ABUFFER_I_H__ +#define __ABUFFER_I_H__ + +namespace openspace { + +class ABuffer_I { +public: + virtual ~ABuffer_I() {}; + virtual bool initialize() = 0; + + virtual void clear() = 0; + virtual void preRender() = 0; + virtual void postRender() = 0; + virtual void resolve() = 0; + +}; // ABuffer_I +} // openspace + +#endif // __ABUFFER_I_H__ \ No newline at end of file diff --git a/include/openspace/abuffer/abufferdynamic.h b/include/openspace/abuffer/abufferdynamic.h new file mode 100644 index 0000000000..23959f08f1 --- /dev/null +++ b/include/openspace/abuffer/abufferdynamic.h @@ -0,0 +1,60 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __ABUFFERDYNAMIC_H__ +#define __ABUFFERDYNAMIC_H__ + +#include + +namespace openspace { + +class ABufferDynamic: public ABuffer { +public: + + ABufferDynamic(); + virtual ~ABufferDynamic(); + virtual bool initialize(); + + virtual void clear(); + virtual void preRender(); + virtual void postRender(); + + virtual std::string settings(); + +private: + + GLuint *_data; + GLuint _anchorPointerTexture; + GLuint _anchorPointerTextureInitializer; + GLuint _atomicCounterBuffer; + GLuint _fragmentBuffer; + GLuint _fragmentTexture; + + + + +}; // ABufferDynamic +} // openspace + +#endif // __ABUFFERDYNAMIC_H__ \ No newline at end of file diff --git a/include/openspace/abuffer/abufferfixed.h b/include/openspace/abuffer/abufferfixed.h new file mode 100644 index 0000000000..cc211e0b57 --- /dev/null +++ b/include/openspace/abuffer/abufferfixed.h @@ -0,0 +1,61 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __ABUFFERFIXED_H__ +#define __ABUFFERFIXED_H__ + +#include + +namespace openspace { + +class ABufferFixed: public ABuffer { +public: + + ABufferFixed(); + virtual ~ABufferFixed(); + virtual bool initialize(); + + virtual void clear(); + virtual void preRender(); + virtual void postRender(); + + virtual std::string settings(); + +private: + + GLuint *_data; + GLuint _anchorPointerTexture; + GLuint _anchorPointerTextureInitializer; + GLuint _atomicCounterBuffer; + GLuint _atomicCounterTexture; + GLuint _fragmentBuffer; + GLuint _fragmentTexture; + + + + +}; // ABufferFixed +} // openspace + +#endif // __ABUFFERFIXED_H__ \ No newline at end of file diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 66fdd720f3..80ea8a7626 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -34,17 +34,34 @@ #include #include -//#define FLARE_ONLY +// #define FLARE_ONLY #include +#include + +#define ABUFFER_SINGLE_LINKED 1 +#define ABUFFER_FIXED 2 +#define ABUFFER_DYNAMIC 3 +#define ABUFFER_IMPLEMENTATION ABUFFER_SINGLE_LINKED + +// #define OPENSPACE_VIDEO_EXPORT + +namespace ghoul { + namespace cmdparser { + class CommandlineParser; + class CommandlineCommand; + } +} namespace openspace { -class ScriptEngine; +namespace scripting { + class ScriptEngine; +} class OpenSpaceEngine { public: - static void create(int argc, char** argv, std::vector& sgctArguments); + static bool create(int argc, char** argv, std::vector& sgctArguments); static void destroy(); static OpenSpaceEngine& ref(); @@ -59,6 +76,8 @@ public: ghoul::opencl::CLContext& clContext(); InteractionHandler& interactionHandler(); RenderEngine& renderEngine(); + scripting::ScriptEngine& scriptEngine(); + ShaderCreator& shaderBuilder(); // SGCT callbacks bool initializeGL(); @@ -70,19 +89,27 @@ public: void mouseButtonCallback(int key, int action); void mousePositionCallback(int x, int y); void mouseScrollWheelCallback(int pos); + void externalControlCallback(const char* receivedChars, int size, int clientId); void encode(); void decode(); private: - OpenSpaceEngine(); + OpenSpaceEngine(std::string programName); ~OpenSpaceEngine(); + bool gatherCommandlineArguments(); + static OpenSpaceEngine* _engine; ghoul::Dictionary* _configurationManager; InteractionHandler* _interactionHandler; RenderEngine* _renderEngine; + scripting::ScriptEngine* _scriptEngine; + ghoul::cmdparser::CommandlineParser* _commandlineParser; +#ifdef OPENSPACE_VIDEO_EXPORT + bool _doVideoExport; +#endif #ifdef FLARE_ONLY Flare* _flare; #endif @@ -90,6 +117,7 @@ private: ghoul::opencl::CLContext _context; sgct::SharedVector _synchronizationBuffer; + ShaderCreator _shaderBuilder; }; #define OsEng (openspace::OpenSpaceEngine::ref()) diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/interactionhandler.h index b8505beda2..80b867dd91 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/interactionhandler.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include namespace openspace { @@ -56,6 +58,8 @@ public: void mouseButtonCallback(int key, int action); void mousePositionCallback(int x, int y); void mouseScrollWheelCallback(int pos); + + void addKeyCallback(int key, std::function f); private: glm::vec3 mapToTrackball(glm::vec2 mousePos); @@ -77,6 +81,8 @@ private: // for locking and unlocking std::mutex cameraGuard_; + + std::multimap > _keyCallbacks; }; diff --git a/include/openspace/interface/interface.h b/include/openspace/interface/interface.h index dcdfcb8fda..3d82632246 100644 --- a/include/openspace/interface/interface.h +++ b/include/openspace/interface/interface.h @@ -66,7 +66,7 @@ private: void handleNodes(); void loadIntoNodes(const boost::property_tree::ptree& tree, std::string parent = "", const int depth = 0); - OpenSpaceEngine* _engine; + // OpenSpaceEngine* _engine; std::vector _nodes; }; diff --git a/include/openspace/properties/numericalproperty.h b/include/openspace/properties/numericalproperty.h index 6050db32da..45d15f9d03 100644 --- a/include/openspace/properties/numericalproperty.h +++ b/include/openspace/properties/numericalproperty.h @@ -38,6 +38,10 @@ public: NumericalProperty(std::string identifier, std::string guiName, T value, T minimumValue, T maximumValue); + bool getLua(lua_State* state) const override; + bool setLua(lua_State* state) override; + int typeLua() const override; + virtual std::string className() const override; using TemplateProperty::operator=; diff --git a/include/openspace/properties/numericalproperty.inl b/include/openspace/properties/numericalproperty.inl index 5fe62f1b89..30ee9ea0d3 100644 --- a/include/openspace/properties/numericalproperty.inl +++ b/include/openspace/properties/numericalproperty.inl @@ -22,43 +22,125 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#include + namespace openspace { namespace properties { -#define REGISTER_NUMERICALPROPERTY_HEADER(CLASS_NAME, TYPE) \ - typedef NumericalProperty CLASS_NAME; \ - template <> std::string PropertyDelegate>::className(); \ - template <> std::string PropertyDelegate>::className(); \ - template <> template <> \ - TYPE PropertyDelegate>::defaultValue(); \ - template <> template <> \ - TYPE PropertyDelegate>::defaultMinimumValue(); \ - template <> template <> \ - TYPE PropertyDelegate>::defaultMaximumValue(); +#define REGISTER_NUMERICALPROPERTY_HEADER(CLASS_NAME, TYPE) \ + typedef NumericalProperty CLASS_NAME; \ + template <> \ + std::string PropertyDelegate>::className(); \ + template <> \ + std::string PropertyDelegate>::className(); \ + template <> \ + template <> \ + TYPE PropertyDelegate>::defaultValue(); \ + template <> \ + template <> \ + TYPE PropertyDelegate>::defaultMinimumValue(); \ + template <> \ + template <> \ + TYPE PropertyDelegate>::defaultMaximumValue(); \ + template <> \ + template <> \ + TYPE PropertyDelegate>::fromLuaValue(lua_State* state, \ + bool& success); \ + template <> \ + template <> \ + TYPE PropertyDelegate>::fromLuaValue(lua_State* state, \ + bool& success); \ + template <> \ + template <> \ + bool PropertyDelegate>::toLuaValue(lua_State* state, \ + TYPE value); \ + template <> \ + template <> \ + bool PropertyDelegate>::toLuaValue(lua_State* state, \ + TYPE value); \ + template <> \ + int PropertyDelegate>::typeLua(); \ + template <> \ + int PropertyDelegate>::typeLua(); - -#define REGISTER_NUMERICALPROPERTY_SOURCE(CLASS_NAME, TYPE, \ - DEFAULT_VALUE, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, DEFAULT_STEPPING) \ - template <> \ - std::string PropertyDelegate>::className() { \ - return #CLASS_NAME; \ -} \ - template <> \ - std::string PropertyDelegate>::className() { \ - return #CLASS_NAME; \ -} \ - template <> template <> \ - TYPE PropertyDelegate>::defaultValue() { \ - return DEFAULT_VALUE; \ -} \ - template <> template <> \ - TYPE PropertyDelegate>::defaultMinimumValue() { \ - return DEFAULT_MIN_VALUE; \ -} \ - template <> template <> \ - TYPE PropertyDelegate>::defaultMaximumValue() { \ - return DEFAULT_MAX_VALUE; \ -} +#define REGISTER_NUMERICALPROPERTY_SOURCE(CLASS_NAME, TYPE, DEFAULT_VALUE, \ + DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE, \ + DEFAULT_STEPPING, FROM_LUA_LAMBDA_EXPRESSION, \ + TO_LUA_LAMBDA_EXPRESSION, LUA_TYPE) \ + template <> \ + std::string PropertyDelegate>::className() \ + { \ + return #CLASS_NAME; \ + \ +} \ + template <> \ + std::string PropertyDelegate>::className() \ + { \ + return PropertyDelegate>::className(); \ + \ +} \ + template <> \ + template <> \ + TYPE PropertyDelegate>::defaultValue() \ + { \ + return DEFAULT_VALUE; \ + \ +} \ + template <> \ + template <> \ + TYPE PropertyDelegate>::defaultMinimumValue() \ + { \ + return DEFAULT_MIN_VALUE; \ + \ +} \ + template <> \ + template <> \ + TYPE PropertyDelegate>::defaultMaximumValue() \ + { \ + return DEFAULT_MAX_VALUE; \ + \ +} \ + template <> \ + template <> \ + TYPE PropertyDelegate>::fromLuaValue(lua_State * state, \ + bool& success) \ + { \ + return FROM_LUA_LAMBDA_EXPRESSION(state, success); \ + \ +} \ + template <> \ + template <> \ + TYPE PropertyDelegate>::fromLuaValue( \ + lua_State * state, bool& success) \ + { \ + return PropertyDelegate>::fromLuaValue(state, \ + success); \ + \ +} \ + template <> \ + template <> \ + bool PropertyDelegate>::toLuaValue(lua_State * state, \ + TYPE value) \ + { \ + return TO_LUA_LAMBDA_EXPRESSION(state, value); \ + } \ + template <> \ + template <> \ + bool PropertyDelegate>::toLuaValue(lua_State * state, \ + TYPE value) \ + { \ + return PropertyDelegate>::toLuaValue(state, value); \ + } \ + template <> \ + int PropertyDelegate>::typeLua() \ + { \ + return LUA_TYPE; \ + } \ + template <> \ + int PropertyDelegate>::typeLua() \ + { \ + return PropertyDelegate>::typeLua(); \ + } // Delegating constructors are necessary; automatic template deduction cannot // deduce template argument for 'U' if 'default' methods are used as default values in @@ -95,5 +177,28 @@ std::string NumericalProperty::className() const { return PropertyDelegate>::className(); } +template +bool NumericalProperty::setLua(lua_State* state) +{ + bool success; + T value = PropertyDelegate>::template fromLuaValue(state, success); + if (success) + TemplateProperty::setValue(value); + return success; +} + +template +bool NumericalProperty::getLua(lua_State* state) const +{ + bool success = PropertyDelegate>::template toLuaValue(state, TemplateProperty::_value); + return success; +} + +template +int NumericalProperty::typeLua() const { + return PropertyDelegate>::typeLua(); +} + + } // namespace properties } // namespace openspace diff --git a/include/openspace/properties/property.h b/include/openspace/properties/property.h index 4dcadd5853..9b042bbed7 100644 --- a/include/openspace/properties/property.h +++ b/include/openspace/properties/property.h @@ -32,43 +32,223 @@ #include #include +struct lua_State; + namespace openspace { namespace properties { class PropertyOwner; +/** + * A property encapsulates a value which should be user-changeable. A property almost + * always belongs to a PropertyOwner who has taken ownership (setPropertyOwner) of the + * Property. Per PropertyOwner, the identifier needs to be unique and can be + * used as a URI. This class is an abstract base class and each subclass (most notable + * TemplateProperty) needs to implement the methods Property::className, Property::get, + * Property::set, Property::type(), Property::getLua, Property::setLua, and + * Property::typeLua to make full use of the infrastructure. + * The most common types can be implemented by creating a specialized instantiation of + * TemplateProperty, which provides default implementations for these methods. + * + * The onChange method can be used by the PropertyOwner to listen to changes that happen + * to the Property. The parameter is a function object that gets called after new value + * has been set. + * The metaData allows the developer to specify additional information about the Property + * which might be used in GUI representations. One example would be a glm::vec4 property, + * (Vec4Property) that can either represent a 4-dimensional position, a powerscaled + * coordinate, a light position, or other things, requiring different GUI representations. + * \see TemplateProperty + * \see PropertyOwner + */ class Property { public: + /** + * The constructor for the property. The identifier needs to be unique + * for each PropertyOwner. The guiName will be stored in the metaData + * to be accessed by the GUI elements using the guiName key. The default + * visibility settings is true, whereas the default read-only state is + * false. + * \param identifier A unique identifier for this property. It has to be unique to the + * PropertyOwner and cannot contain any .s + * \param guiName The human-readable GUI name for this Property + */ Property(std::string identifier, std::string guiName); + + /** + * The destructor taking care of deallocating all unused memory. This method will not + * remove the Property from the PropertyOwner. + */ virtual ~Property(); - //virtual Property* create() const = 0; + /** + * This method returns the class name of the Property. The method is used by the + * TemplateFactory to create new instances of Propertys. The returned value is almost + * always identical to the C++ class name of the derived class. + * \return The class name of the Property + */ virtual std::string className() const = 0; + /** + * This method returns the encapsulated value of the Property to the caller. The type + * that is returned is determined by the type function and is up to the developer of + * the derived class. The default implementation returns an empty boost::any object. + * \return The value that is encapsulated by this Property, or an empty boost::any + * object if the method was not overritten. + */ virtual boost::any get() const; - virtual void set(boost::any value); - virtual const std::type_info& type() const; + /** + * Sets the value encapsulated by this Property to the value passed to + * this function. It is the caller's responsibility to ensure that the type contained + * in value is compatible with the concrete subclass of the Property. The + * method Property::type will return the desired type for the Property. The default + * implementation of this method ignores the input. + * \param value The new value that should be stored in this Property + */ + virtual void set(boost::any value); + + /** + * This method returns the type that is requested by this Property for the set method. + * The default implementation returns the type of void. + * \return The type that is requested by this Property's Property::set method + */ + virtual const std::type_info& type() const; + + /** + * This method encodes the encapsulated value of this Property at the top of the Lua + * stack. The specific details of this serialization is up to the property developer + * as long as the rest of the stack is unchanged. The implementation has to be + * synchronized with the Property::setLua method. The default implementation is a + * no-op. + * \param state The Lua state to which the value will be encoded + * \return true if the encoding succeeded, false otherwise + */ + virtual bool getLua(lua_State* state) const; + + /** + * This method sets the value encapsulated by this Property by deserializing the value + * on top of the passed Lua stack. The specific details of the deserialization are up + * to the Property developer, but they must only depend on the top element of the + * stack and must leave all other elements unchanged. The implementation has to be + * synchronized with the Property::getLua method. The default implementation is a + * no-op. + * \param state The Lua state from which the value will be decoded + * \return true if the decoding and setting of the value succeeded, + * false otherwise + */ + virtual bool setLua(lua_State* state); + + /** + * Returns the Lua type that will be put onto the stack in the Property::getLua method + * and which will be consumed by the Property::setLua method. The returned value + * can belong to the set of Lua types: LUA_TNONE, LUA_TNIL, + * LUA_TBOOLEAN, LUA_TLIGHTUSERDATA, + * LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE, + * LUA_TFUNCTION, LUA_TUSERDATA, or + * LUA_TTHREAD. The default implementation will return + * LUA_TNONE. + * \return The Lua type that will be consumed or produced by the Property::getLua and + * Property::setLua methods. + */ + virtual int typeLua() const; + + /** + * This method registers a callback function that will be called every + * time if either Property:set or Property::setLua was called with a value that is + * different from the previously stored value. The callback can be removed my passing + * an empty std::function object. + * \param callback The callback function that is called when the encapsulated type has + * been successfully changed by either the Property::set or Property::setLua methods. + */ virtual void onChange(std::function callback); + /** + * This method returns the unique identifier of this Property. + * \return The unique identifier of this Property + */ const std::string& identifier() const; - const std::string& guiName() const; + /** + * Returns the PropertyOwner of this Property or nullptr, if it does not + * have an owner. + *\ return The Property of this Property + */ PropertyOwner* owner() const; - void setPropertyOwner(PropertyOwner* owner); + /** + * Assigned the Property to a new PropertyOwner. This method does not inform the + * PropertyOwner of this action. + * \param owner The new PropertyOwner for this Property + */ + void setPropertyOwner(PropertyOwner* owner); + + /** + * Returns the human-readable GUI name for this Property that has been set in the + * constructor. This method returns the same value as accessing the metaData object + * and requesting the std::string stored for the guiName + * key. + * \return The human-readable GUI name for this Property + */ + const std::string& guiName() const; + + /** + * Sets the identifier of the group that this Property belongs to. Property groups can + * be used, for example, by GUI application to visually group different properties, + * but it has no impact on the Property itself. The default value for the groupID is + * "". + * \param groupId The group id that this property should belong to + */ void setGroupIdentifier(std::string groupId); + + /** + * Returns the group idenfier that this Property belongs to, or "" if it + * belongs to no group. + * \return The group identifier that this Property belongs to + */ std::string groupIdentifier() const; + /** + * Determines a hint if this Property should be visible, or hidden. Each application + * accessing the properties is free to ignore this hint. It is stored in the metaData + * Dictionary with the key: isVisible. The default value is + * true. + * \param state true if the Property should be visible, + * false otherwise. + */ void setVisible(bool state); - bool isVisible() const; - void setReadOnly(bool state); - bool isReadOnly() const; + /** + * This method determines if this Property should be read-only in external + * applications. This setting is only a hint and does not need to be followed by GUI + * applications and does not have any effect on the Property::set or Property::setLua + * methods. The value is stored in the metaData Dictionary with the key: + * isReadOnly. The default value is false. + * \param state true if the Property should be read only, + * false otherwise + */ + void setReadOnly(bool state); + /** + * This method allows the developer to give hints to the GUI about different + * representations for the GUI. The same Property (for example Vec4Property) can be + * used in different ways, each requiring a different input method. These values are + * stored in the metaData object using the views. prefix in front of the + * option parameter. See Property::ViewOptions for a default list of + * possible options. As these are only hints, the GUI is free to ignore any suggestion + * by the developer. + * \param option The view option that should be modified + * \param value Determines if the view option should be active (true) or + * deactivated (false) + */ void setViewOption(std::string option, bool value = true); - bool viewOption(const std::string& option) const; + /** + * Default view options that can be used in the Property::setViewOption method. The + * values are: Property::ViewOptions::Color = color, + * Property::ViewOptions::LightPosition = lightPosition, + * Property::ViewOptions::PowerScaledScalar = powerScaledScalar, and + * Property::ViewOptions::PowerScaledCoordinate = powerScaledCoordinate. + */ struct ViewOptions { static const std::string Color; static const std::string LightPosition; @@ -76,16 +256,32 @@ public: static const std::string PowerScaledCoordinate; }; + /** + * Returns the metaData that contains all information for external applications to + * correctly display information about the Property. No information that is stored in + * this Dictionary is necessary for the programmatic use of the Property. + * \return The Dictionary containing all meta data information about this Property + */ const ghoul::Dictionary& metaData() const; protected: - PropertyOwner* _owner; + /** + * This method must be called by all subclasses whenever the encapsulated value has + * changed and a potential listener has to be informed. + */ + void notifyListener(); + /// The PropetyOwner this Property belongs to, or nullptr + PropertyOwner* _owner; + + /// The identifier for this Property std::string _identifier; - std::string _guiName; + + /// The Dictionary containing all meta data necessary for external applications ghoul::Dictionary _metaData; - std::vector> _onChangeCallbacks; + /// The callback function that will be invoked whenever the encapsulated value changes + std::function _onChangeCallback; }; } // namespace properties diff --git a/include/openspace/properties/propertydelegate.h b/include/openspace/properties/propertydelegate.h index 9a090f317c..2b6dd07651 100644 --- a/include/openspace/properties/propertydelegate.h +++ b/include/openspace/properties/propertydelegate.h @@ -27,22 +27,115 @@ #include +struct lua_State; + namespace openspace { namespace properties { +/** + * The PropertyDelegate class is used by (among others) the TemplateProperty and the + * NumericalProperty classes to outsource the definitions of class names, default values, + * etc. Using the PropertyDelegate, it is possible to create new TemplateProperty types + * without subclassing the TemplateProperty, but rather creating a specialized instance + * of PropertyDelegate. See (http://openspace.itn.liu.se/trac/wiki/guides/properties) for + * more detailed information. + * \see TemplateProperty + * \see NumericalProperty + * \tparam T The full class for which this specialized instance of PropertyDelegate is + * responsible. For example T = TemplateProperty. + */ template class PropertyDelegate { public: + /** + * This method returns the class name for the class T. The default + * implementation will lead to a compile-time error if the class method is not + * specialized. + * \return The class name for the class T + */ static std::string className(); + /** + * This method will return the preferred default value for the class T. + * The default implementation will lead to a compile-time error if the class method is + * not specialized. + * \return The default value that the class T should use + * \tparam U The type by which the class T is specialized. If + * T = TemplateProperty, then U = std::string + */ template static U defaultValue(); + /** + * This method will return the preferred default minimum value for the class + * T. The default implementation will lead to a compile-time error if the + * class method is not specialized. This method is not used in TemplateProperty, but + * only NumericalProperty, so the TemplateProperty does not require this method to be + * specialized. + * \return The default minimum value that the class T should use + * \tparam U The type by which the class T is specialized. If + * T = NumericalProperty, then U = int + */ template static U defaultMinimumValue(); + /** + * This method will return the preferred default maximum value for the class + * T. The default implementation will lead to a compile-time error if the + * class method is not specialized. This method is not used in TemplateProperty, but + * only NumericalProperty, so the TemplateProperty does not require this method to be + * specialized. + * \return The default maximum value that the class T should use + * \tparam U The type by which the class T is specialized. If + * T = NumericalProperty, then U = int + */ template static U defaultMaximumValue(); + + /** + * This method converts the top value from the Lua stack into a value of type + * U and reports the success back to the caller. The default + * implementation will lead to a compile-time error if the class method is not + * specialized. + * \param state The Lua state from which the value is retrieved + * \param success Will be true if the conversion succeeded; + * false otherwise + * \return The value that was created by converting the top value from the stack + * \tparam U The type by which the class T is specialized. If + * T = TemplateProperty, then U = std::string + */ + template + static U fromLuaValue(lua_State* state, bool& success); + + /** + * This method converts the passed value, encodes it and places it on the + * top value of the Lua stack and returns the success back to the caller. The default + * implementation will lead to a compile-time error if the class method is not + * specialized. + * \param state The Lua state from which the value is retrieved + * \param value The value that will be converted into a Lua object + * \return true if the conversion succeeded; false otherwise + * \tparam U The type by which the class T is specialized. If + * T = TemplateProperty, then U = std::string + */ + template + static bool toLuaValue(lua_State* state, U value); + + /** + * Returns the Lua type that will be put onto the stack in the + * PropertyDelegate::toLuaValue method and which will be consumed by the + * PropertyDelegate::fromLuaValue method. The returned value can belong to the set of + * Lua types: LUA_TNONE, LUA_TNIL, + * LUA_TBOOLEAN, LUA_TLIGHTUSERDATA, + * LUA_TNUMBER, LUA_TSTRING, LUA_TTABLE, + * LUA_TFUNCTION, LUA_TUSERDATA, or + * LUA_TTHREAD. The default implementation will return + * LUA_TNONE. The default implementation will lead to a compile-time + * error if the class method is not specialized. + * \return The Lua type that will be consumed or produced by the + * PropertyDelegate::toLuaValue and PropertyDelegate::fromLuaValue methods. + */ + static int typeLua(); }; } // namespace properties diff --git a/include/openspace/properties/propertydelegate.inl b/include/openspace/properties/propertydelegate.inl index 5af2f6013e..584f2a3098 100644 --- a/include/openspace/properties/propertydelegate.inl +++ b/include/openspace/properties/propertydelegate.inl @@ -24,22 +24,20 @@ #include -#include - -#include - namespace openspace { namespace properties { template std::string PropertyDelegate::className() { - static_assert(sizeof(T) == 0, "Unimplemented PropertyDelegate::className specialization"); + static_assert(sizeof(T) == 0, + "Unimplemented PropertyDelegate::className specialization"); } template template U PropertyDelegate::defaultValue() { - static_assert(sizeof(T) == 0, "Unimplemented PropertyDelegate::defaultValue specialization"); + static_assert(sizeof(T) == 0, + "Unimplemented PropertyDelegate::defaultValue specialization"); } template @@ -49,7 +47,6 @@ U PropertyDelegate::defaultMinimumValue() { "Unimplemented PropertyDelegate::defaultMinimumValue specialization"); } - template template U PropertyDelegate::defaultMaximumValue() { @@ -57,5 +54,25 @@ U PropertyDelegate::defaultMaximumValue() { "Unimplemented PropertyDelegate::defaultMaximumValue specialization"); } +template +template +U PropertyDelegate::fromLuaValue(lua_State* state, bool& success) { + static_assert(sizeof(T) == 0, + "Unimplemented PropertyDelegate::fromLuaValue specialization"); +} + +template +template +bool PropertyDelegate::toLuaValue(lua_State* state, U value) { + static_assert(sizeof(T) == 0, + "Unimplemented PropertyDelegate::toLuaValue specialization"); +} + +template +int PropertyDelegate::typeLua() { + static_assert(sizeof(T) == 0, + "Unimplemented PropertyDelegate::luaType specialization"); +} + } // namespace properties } // namespace openspace diff --git a/include/openspace/properties/propertyowner.h b/include/openspace/properties/propertyowner.h index 6211c877b4..7e29af385b 100644 --- a/include/openspace/properties/propertyowner.h +++ b/include/openspace/properties/propertyowner.h @@ -33,29 +33,178 @@ namespace openspace { namespace properties { +/** + * A PropertyOwner can own Propertys or other PropertyOwner and provide access to both in + * a unified way. The identifiers and names of Propertys and + * sub-owners must be unique to this PropertyOwner. A Property cannot have the same name + * as a PropertyOwner owned by this PropertyOwner. + * Propertys can be added using the Property::addProperty methods and be removed by the + * Property::removeProperty method. The same holds true for sub-owners + * (Property::addPropertySubOwner, Property::removePropertySubOwner). These methods will + * inform the passed object about the new ownership automatically. + * Stored properties can be accessed using the Property::properties method or the + * Property::property method, providing an URI for the location of the property. If the + * URI contains separators (.), the first name before the separator will be + * used as a subOwner's name and the search will proceed recursively. + */ class PropertyOwner { public: + /// The separator that is used while accessing the properties and/or sub-owners + static const char URISeparator = '.'; + + /// The constructor initializing the PropertyOwner's name to "" PropertyOwner(); + + /** + * The destructor will remove all Propertys and PropertyOwners it owns along with + * itself. + */ virtual ~PropertyOwner(); + /** + * Sets the name for this PropertyOwner. If the PropertyOwner does not have an owner + * itself, the name must be globally unique. If the PropertyOwner has an owner, the + * name must be unique to the owner (including the owner's properties). No uniqueness + * check will be preformed here, but rather in the PropertyOwner::addProperty and + * PropertyOwner::addPropertySubOwner methods). + * \param name The name of this PropertyOwner. It may not contain any .s + */ void setName(std::string name); - virtual const std::string& name() const; + + /** + * Returns the name of this PropertyOwner. + * \return The name of this PropertyOwner + */ + const std::string& name() const; + + /** + * Returns a list of all Propertys directly owned by this PropertyOwner. This list not + * include Propertys owned by other sub-owners. + * \return A list of all Propertys directly owned by this PropertyOwner + */ const std::vector& properties() const; - Property* property(const std::string& id) const; + /** + * Retrieves a Property identified by URI from this PropertyOwner. If + * id does not contain a . the identifier must refer to a + * Property directly owned by this PropertyOwner. If the identifier contains one or + * more ., the first part of the name will be recursively extracted and + * used as a name for a sub-owner and only the last part of the identifier is + * referring to a Property owned by PropertyOwner named by the second-but-last name. + * \param URI The identifier of the Property that should be extracted. If the Property + * cannot be found, nullptr is returned + */ + Property* property(const std::string& URI) const; + + /** + * This method checks if a Property with the provided URI exists in this + * PropertyOwner (or any sub-owner). If the identifier contains one or more + * ., the first part of the name will be recursively extracted and is + * used as a name for a sub-owner and only the last part of the identifier is + * referring to a Property owned by PropertyOwner named by the second-but-last name. + * \return true if the URI refers to a Property; + * false otherwise. + */ + bool hasProperty(const std::string& URI) const; + + /** + * Returns a list of all sub-owners this PropertyOwner has. Each name of a sub-owner + * has to be unique with respect to other sub-owners as well as Property's owned by + * this PropertyOwner. + * \return A list of all sub-owners this PropertyOwner has + */ + const std::vector& subOwners() const; + + /** + * This method returns the direct sub-owner of this PropertyOwner with the provided + * name. This means that name cannot contain any + * . as this character is not allowed in PropertyOwner names. If the + * name does not name a valid sub-owner of this PropertyOwner, a + * nullptr will be returned. + * \param name The name of the sub-owner that should be returned + * \return The PropertyOwner with the given name, or nullptr + */ + PropertyOwner* subOwner(const std::string& name) const; + + /** + * Returns true if this PropertyOwner owns a sub-owner with the provided + * name; returns false otherwise. + * \param name The name of the sub-owner that should be looked up + * \return true if this PropertyOwner owns a sub-owner with the provided + * name; returns false otherwise + */ + bool hasSubOwner(const std::string& name) const; + + /** + * This method converts a provided groupID, used by the Propertys, into a + * human-readable name which can be used by some external application. + * \param groupID The group identifier whose human-readable name should be set + * \param name The human-readable name for the group identifier + */ void setPropertyGroupName(std::string groupID, std::string name); + + /** + * Returns the human-readable name for the groupID for the Propertys of + * this PropertyOwner. + * \param groupID The group identifier whose human-readable name should be returned + * \return The human readable name for the Propertys identified by + * groupID + */ const std::string& propertyGroupName(const std::string& groupID) const; - + protected: + /** + * Assigns the Property prop to this PropertyOwner. This method will + * check if the name of the Property is unique amongst Propertys and sub-owners in + * this PropertyOwner. This method will also inform the Property about the change in + * ownership by calling the Property::setPropertyOwner method. + * \param prop The Property whose ownership is changed. + */ void addProperty(Property* prop); + + /// \see Property::addProperty(Property*) void addProperty(Property& prop); + + /** + * Adds the provided PropertyOwner to the list of sub-owners for this PropertyOwner. + * This means that the name of the owner has to be unique amonst the + * direct Property's as well as other PropertyOwner's that this PropertyOwner owns. + * This uniqueness will be tested in this method. + * \param owner The owner that should be assigned to this PropertyOwner + */ + void addPropertySubOwner(PropertyOwner* owner); + /// \see PropertyOwner::addPropertySubOwner(PropertyOwner*) + void addPropertySubOwner(PropertyOwner& owner); + + /** + * Removes the Property from this PropertyOwner. Notifies the Property about this + * change by calling the Property::setPropertyOwner method with a nullptr + * as parameter. + * \param prop The Property that should be removed from this PropertyOwner + */ void removeProperty(Property* prop); + + /// \see PropertyOwner::removeProperty(Property*) void removeProperty(Property& prop); + + /** + * Removes the sub-owner from this PropertyOwner. + * \param owner The PropertyOwner that should be removed + */ + void removePropertySubOwner(PropertyOwner* owner); + + /// \see PropertyOwner::removePropertySubOwner(PropertyOwner*) + void removePropertySubOwner(PropertyOwner& owner); private: + /// The name of this PropertyOwner std::string _name; + /// A list of all owned Property's std::vector _properties; + /// A list of all sub-owners + std::vector _subOwners; + /// The associations between group identifiers of Property's and human-readable names std::map _groupNames; }; diff --git a/include/openspace/properties/stringproperty.h b/include/openspace/properties/stringproperty.h index c1dc995c86..98b9020664 100644 --- a/include/openspace/properties/stringproperty.h +++ b/include/openspace/properties/stringproperty.h @@ -30,23 +30,7 @@ namespace openspace { namespace properties { -class StringProperty : public TemplateProperty { -public: - StringProperty(std::string identifier, std::string guiName); - StringProperty(std::string identifier, std::string guiName, std::string value); - - using TemplateProperty::operator=; -}; - -template <> -std::string PropertyDelegate>::className(); - -template <> -template <> -std::string PropertyDelegate>::defaultValue(); - -//REGISTER_TEMPLATEPROPERTY_HEADER(StringProperty, std::string); - +REGISTER_TEMPLATEPROPERTY_HEADER(StringProperty, std::string); } // namespace properties } // namespace openspace diff --git a/include/openspace/properties/templateproperty.h b/include/openspace/properties/templateproperty.h index d38e0cc660..f2e511ab15 100644 --- a/include/openspace/properties/templateproperty.h +++ b/include/openspace/properties/templateproperty.h @@ -30,24 +30,144 @@ namespace openspace { namespace properties { +/** + * This concrete subclass of Property handles a single parameter value that is of type + * T. It provides all the necessary methods to automatically access the + * value. One notable instantiation of this class is StringProperty, using + * T = std::string while NumericalProperty is a templated subclass dealing + * with numerical parameter types. + * The accessor operator and assignment operators are overloaded, so that the + * TemplateProperty can be used just in the same way as a regular member variable. In the + * case that these cannot not be used inline, the Property::get method will work. + * The default value for the stored value of this TemplateProperty is retrieved via a call + * to the PropertyDelegate::defaultValue method, providing the template parameter + * T as argument. When a new TemplateProperty is required, that method needs + * to be specialized for the new type or a compile-time error will occur + * (See http://openspace.itn.liu.se/trac/wiki/guides/properties). + * \tparam T The type of value that is stored in this TemplateProperty + * \see Property + * \see NumericalProperty + * \see PropertyDelegate + */ template class TemplateProperty : public Property { public: + /** + * The constructor initializing the TemplateProperty with the provided + * identifier and human-readable guiName. The default value + * for the stored type T is retrieved using the PropertyDelegate's + * PropertyDelegate::defaultValue method, which must be specialized for new types or + * a compile-error will occur. + * \param identifier The identifier that is used for this TemplateProperty + * \param guiName The human-readable GUI name for this TemplateProperty + */ TemplateProperty(std::string identifier, std::string guiName); + + /** + * The constructor initializing the TemplateProperty with the provided + * identifier, human-readable guiName and provided + * value. + */ TemplateProperty(std::string identifier, std::string guiName, T value); + /** + * Returns the class name for this TemplateProperty. The default implementation makes + * a call to the PropertyDelegate::className method with the template parameter + * T as argument. For this to work, that method needs to be specialized + * to return the correct class name for the new template parameter T, or a + * compile-time error will occur. + * \return The class name for the TemplateProperty + */ virtual std::string className() const override; + + /** + * Returns the stored value packed into a boost::any object. + * \return The stored value packed into a boost::any object + */ virtual boost::any get() const override; + + /** + * Sets the value fro the provided boost::any object. If the types + * between T and value disagree, an error is logged and the + * stored value remains unchanged. + */ virtual void set(boost::any value) override; + + /** + * Returns the std::type_info describing the template parameter + * T. It can be used to test against a boost::any value + * before trying to assign it. + * \return The type info object describing the template parameter T + */ virtual const std::type_info& type() const override; + /** + * This method encodes the stored value into a Lua object and pushes that object onto + * the stack. The encoding is performed by calling PropertyDelegate::toLuaValue with + * the template parameter T as an argument. This method has to be + * specialized for each new type, or a compile-time error will occur. + * \param state The Lua state onto which the encoded object will be pushed + * \return true if the encoding succeeded; false otherwise + */ + bool getLua(lua_State* state) const override; + + /** + * Sets the value of this TemplateProprty by decoding the object at the top of the Lua + * stack and, if successful, assigning it using the Property::set method. The decoding + * is performed by calling the PropertyDelegate::fromLuaValue with the template + * parameter T as argument. If the decoding is successful, the new value + * is set, otherwise it remains unchanged. + * \param state The Lua state from which the value will be decoded + * \return true if the decoding succeeded; false otherwise + */ + bool setLua(lua_State* state) override; + + /// \see Property::typeLua + int typeLua() const override; + + /** + * This operator allows the TemplateProperty to be used almost transparently as if it + * was of the type T. It makes assignments such as + * T v = property; possible by allowing implicit casts (even though, + * internally, not casts are performed. This method is next to zero overhead). + * \return The internal representation of the Property + */ operator T(); + + /** + * This operator allows the TemplateProperty to be used almost transparently as if it + * was of the type T. It makes assignments such as + * T v = property; possible by allowing implicit casts (even though, + * internally, not casts are performed. This method is next to zero overhead). + * \return The internal representation of the Property + */ + operator T() const; + + /** + * The assignment operator allows the TemplateProperty's value to be set without using + * the TemplateProperty::set method. It will be done internally by thos method and it + * allows assignments such as prop = T(1). + * \param val The value that should be set. + */ TemplateProperty& operator=(T val); + /** + * These method sets the stored value to the provided value val, + * moving it into place. This move only happens if the provided value val + * is different from the stored value, which needs an operator== to exist for the type + * T. If the value are different, the listeners are notified. + * \param val The new value for this TemplateProperty + */ void setValue(T val); + + /** + * Returns the currently stored value. + * \return The currently stored value + */ T value() const; protected: + /// The value that this TemplateProperty currently stores T _value; }; diff --git a/include/openspace/properties/templateproperty.inl b/include/openspace/properties/templateproperty.inl index 6b48c02473..5459d644ef 100644 --- a/include/openspace/properties/templateproperty.inl +++ b/include/openspace/properties/templateproperty.inl @@ -25,26 +25,82 @@ namespace openspace { namespace properties { +// The following macros can be used to quickly generate the necessary PropertyDelegate +// specializations required by the TemplateProperty class. Use the +// REGISTER_TEMPLATEPROPERTY_HEADER macro in the header file and the +// REGISTER_TEMPLATEPROPERTY_SOURCE macro in the source file of your new specialization of +// a TemplateProperty + + +// CLASS_NAME = The string that the Property::className() should return as well as the +// C++ class name for which a typedef will be created +// TYPE = The template parameter T for which the TemplateProperty is specialized #define REGISTER_TEMPLATEPROPERTY_HEADER(CLASS_NAME, TYPE) \ typedef TemplateProperty CLASS_NAME; \ template <> \ std::string PropertyDelegate>::className(); \ template <> \ template <> \ - TYPE PropertyDelegate>::defaultValue(); + TYPE PropertyDelegate>::defaultValue(); \ + template <> \ + template <> \ + TYPE PropertyDelegate>::fromLuaValue(lua_State* state, \ + bool& success); \ + template <> \ + template <> \ + bool PropertyDelegate>::toLuaValue(lua_State* state, \ + TYPE value); \ + template <> \ + int PropertyDelegate>::typeLua(); -#define REGISTER_TEMPLATEPROPERTY_SOURCE(CLASS_NAME, TYPE, DEFAULT_VALUE) \ +// CLASS_NAME = The string that the Property::className() should return as well as the +// C++ class name for which a typedef will be created +// TYPE = The template parameter T for which the TemplateProperty is specialized +// DEFAULT_VALUE = The value (as type T) which should be used as a default value +// FROM_LUA_LAMBDA_EXPRESSION = A lambda expression receiving a lua_State* as the first +// parameter, a bool& as the second parameter and returning +// a value T. It is used by the fromLua method of +// TemplateProperty. The lambda expression must extract the +// stored value from the lua_State, return the value and +// report success in the second argument +// TO_LUA_LAMBDA_EXPRESSION = A lambda expression receiving a lua_State*, a value T and +// returning a bool. The lambda expression must encode the +// value T onto the lua_State stack and return the success +// LUA_TYPE = The Lua type that will be produced/consumed by the previous +// Lambda expressions +#define REGISTER_TEMPLATEPROPERTY_SOURCE(CLASS_NAME, TYPE, DEFAULT_VALUE, \ + FROM_LUA_LAMBDA_EXPRESSION, \ + TO_LUA_LAMBDA_EXPRESSION, LUA_TYPE) \ template <> \ - std::string PropertyDelegate>::className() { \ + std::string PropertyDelegate>::className() \ + { \ return #CLASS_NAME; \ - \ -} \ + } \ template <> \ template <> \ - TYPE PropertyDelegate>::defaultValue() { \ + TYPE PropertyDelegate>::defaultValue() \ + { \ return DEFAULT_VALUE; \ - \ -} + } \ + template <> \ + template <> \ + TYPE PropertyDelegate>::fromLuaValue(lua_State * state, \ + bool& success) \ + { \ + return FROM_LUA_LAMBDA_EXPRESSION(state, success); \ + } \ + template <> \ + template <> \ + bool PropertyDelegate>::toLuaValue(lua_State * state, \ + TYPE value) \ + { \ + return TO_LUA_LAMBDA_EXPRESSION(state, value); \ + } \ + template <> \ + int PropertyDelegate>::typeLua() \ + { \ + return LUA_TYPE; \ + } // Delegating constructors are necessary; automatic template deduction cannot // deduce template argument for 'U' if 'default' methods are used as default values in @@ -52,15 +108,17 @@ namespace properties { template TemplateProperty::TemplateProperty(std::string identifier, std::string guiName) - : TemplateProperty(std::move(identifier), std::move(guiName), - PropertyDelegate>::template defaultValue()) { + : TemplateProperty( + std::move(identifier), std::move(guiName), + PropertyDelegate>::template defaultValue()) +{ } template TemplateProperty::TemplateProperty(std::string identifier, std::string guiName, T value) : Property(std::move(identifier), std::move(guiName)) - , _value(value) { + , _value(std::move(value)) { } template @@ -73,6 +131,11 @@ TemplateProperty::operator T() { return _value; } +template +TemplateProperty::operator T() const { + return _value; +} + template TemplateProperty& TemplateProperty::operator=(T val) { setValue(val); @@ -88,7 +151,11 @@ T openspace::properties::TemplateProperty::value() const template void openspace::properties::TemplateProperty::setValue(T val) { - _value = val; + const bool changed = (val != _value); + if (changed) { + _value = std::move(val); + notifyListener(); + } } @@ -100,10 +167,15 @@ boost::any TemplateProperty::get() const { template void TemplateProperty::set(boost::any value) { try { - _value = boost::any_cast(std::move(value)); + T v = boost::any_cast(std::move(value)); + if (v != _value) { + _value = std::move(v); + notifyListener(); + } } catch (boost::bad_any_cast&) { - LERRORC("TemplateProperty", "Illegal cast to '" << typeid(T).name() << "'"); + LERRORC("TemplateProperty", "Illegal cast from '" << value.type().name() + << "' to '" << typeid(T).name() << "'"); } } @@ -112,5 +184,27 @@ const std::type_info& TemplateProperty::type() const { return typeid(T); } +template +bool TemplateProperty::setLua(lua_State* state) +{ + bool success; + T thisValue = PropertyDelegate>::template fromLuaValue(state, success); + if (success) + set(boost::any(thisValue)); + return success; +} + +template +bool TemplateProperty::getLua(lua_State* state) const +{ + bool success = PropertyDelegate>::template toLuaValue(state, _value); + return success; +} + +template +int TemplateProperty::typeLua() const { + return PropertyDelegate>::typeLua(); +} + } // namespace properties } // namespace openspace diff --git a/include/openspace/properties/vectorproperty.h b/include/openspace/properties/vectorproperty.h index 97124be115..583fe28c30 100644 --- a/include/openspace/properties/vectorproperty.h +++ b/include/openspace/properties/vectorproperty.h @@ -49,25 +49,6 @@ REGISTER_NUMERICALPROPERTY_HEADER(UVec2Property, glm::uvec2); REGISTER_NUMERICALPROPERTY_HEADER(UVec3Property, glm::uvec3); REGISTER_NUMERICALPROPERTY_HEADER(UVec4Property, glm::uvec4); -//REGISTER_NUMERICALPROPERTY_HEADER(CharProperty, char); -////REGISTER_NUMERICALPROPERTY_HEADER(Char16Property, char16_t); -////REGISTER_NUMERICALPROPERTY_HEADER(Char32Property, char32_t); -//REGISTER_NUMERICALPROPERTY_HEADER(WCharProperty, wchar_t); -//REGISTER_NUMERICALPROPERTY_HEADER(SignedCharProperty, signed char); -//REGISTER_NUMERICALPROPERTY_HEADER(UCharProperty, unsigned char); -//REGISTER_NUMERICALPROPERTY_HEADER(ShortProperty, short); -//REGISTER_NUMERICALPROPERTY_HEADER(UShortProperty, unsigned short); -//REGISTER_NUMERICALPROPERTY_HEADER(IntProperty, int); -//REGISTER_NUMERICALPROPERTY_HEADER(UIntProperty, unsigned int); -//REGISTER_NUMERICALPROPERTY_HEADER(LongProperty, long); -//REGISTER_NUMERICALPROPERTY_HEADER(ULongProperty, unsigned long); -//REGISTER_NUMERICALPROPERTY_HEADER(LongLongProperty, long long); -//REGISTER_NUMERICALPROPERTY_HEADER(ULongLongProperty, unsigned long long); -//REGISTER_NUMERICALPROPERTY_HEADER(FloatProperty, float); -//REGISTER_NUMERICALPROPERTY_HEADER(DoubleProperty, double); -//REGISTER_NUMERICALPROPERTY_HEADER(LongDoubleProperty, long double); - - } // namespace properties } // namespace openspace diff --git a/include/openspace/query/query.h b/include/openspace/query/query.h index 3d2bbd1249..1bd1edf34b 100644 --- a/include/openspace/query/query.h +++ b/include/openspace/query/query.h @@ -29,12 +29,15 @@ namespace openspace { +namespace properties { + class Property; +} class SceneGraph; class SceneGraphNode; -SceneGraph* getSceneGraph(); - -SceneGraphNode* getSceneGraphNode(const std::string& name); +SceneGraph* sceneGraph(); +SceneGraphNode* sceneGraphNode(const std::string& name); +properties::Property* property(const std::string& uri); } // namespace diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 2ff4bda48a..91c001e5d7 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -25,12 +25,13 @@ #ifndef __RENDERABLE_H__ #define __RENDERABLE_H__ -// open space includes +#include + +#include #include #include #include #include -#include namespace openspace { @@ -51,10 +52,16 @@ public: virtual void render(const Camera* camera, const psc& thisPosition) = 0; virtual void update(); + bool isVisible() const; + protected: - // Renderable(); + std::string findPath(const std::string& path); + private: + properties::BoolProperty _enabled; + PowerScaledScalar boundingSphere_; + std::string _relativePath; }; } // namespace openspace diff --git a/include/openspace/rendering/renderablefieldlines.h b/include/openspace/rendering/renderablefieldlines.h new file mode 100644 index 0000000000..e250a7e4d5 --- /dev/null +++ b/include/openspace/rendering/renderablefieldlines.h @@ -0,0 +1,71 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef RENDERABLEFIELDLINES_H_ +#define RENDERABLEFIELDLINES_H_ + +// open space includes +#include + +// ghoul includes +#include +#include + +namespace openspace { + struct LinePoint; + +class RenderableFieldlines : public Renderable { +public: + RenderableFieldlines(const ghoul::Dictionary& dictionary); + ~RenderableFieldlines(); + + bool initialize(); + bool deinitialize(); + + virtual void render(const Camera *camera, const psc& thisPosition); + virtual void update(); + +private: + std::vector > getFieldlinesData(std::string filename, ghoul::Dictionary hintsDictionary); + + std::vector _hintsDictionaries; + std::vector _filenames; + std::vector _seedPoints; + + ghoul::opengl::ProgramObject *_fieldlinesProgram; + GLuint _VAO, _seedpointVAO; + + ghoul::filesystem::File* _vertexSourceFile; + ghoul::filesystem::File* _fragmentSourceFile; + + std::vector _lineStart; + std::vector _lineCount; + + bool _programUpdateOnSave; + bool _update; + void safeShaderCompilation(); +}; + +} // namespace openspace +#endif // RENDERABLEFIELDLINES_H_ diff --git a/include/openspace/rendering/renderablevolume.h b/include/openspace/rendering/renderablevolume.h index 00bc8c680b..9c9c1c4b9c 100644 --- a/include/openspace/rendering/renderablevolume.h +++ b/include/openspace/rendering/renderablevolume.h @@ -29,7 +29,6 @@ #include // ghoul includes -#include #include #include @@ -37,23 +36,19 @@ namespace openspace { class RenderableVolume: public Renderable { public: - // constructors & destructor RenderableVolume(const ghoul::Dictionary& dictionary); ~RenderableVolume(); protected: - std::string findPath(const std::string& path); ghoul::opengl::Texture* loadVolume(const std::string& filepath, const ghoul::Dictionary& hintsDictionary); + glm::vec3 getVolumeOffset(const std::string& filepath, const ghoul::Dictionary& hintsDictionary); ghoul::RawVolumeReader::ReadHints readHints(const ghoul::Dictionary& dictionary); ghoul::opengl::Texture* loadTransferFunction(const std::string& filepath); private: - - // relative path - std::string _relativePath; }; } // namespace openspace -#endif \ No newline at end of file +#endif diff --git a/include/openspace/rendering/renderablevolumecl.h b/include/openspace/rendering/renderablevolumecl.h index cb7ab38790..43d5ad71a0 100644 --- a/include/openspace/rendering/renderablevolumecl.h +++ b/include/openspace/rendering/renderablevolumecl.h @@ -1,105 +1,106 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __RENDERABLEVOLUMECL_H__ -#define __RENDERABLEVOLUMECL_H__ - -// open space includes -#include - -// ghoul includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SGCT_WINDOWS_INCLUDE -#include - -namespace sgct_utils { - class SGCTBox; -} - -//#include -//#include -#ifdef __APPLE__ - #include -#else - #include -#endif - -namespace openspace { - -class RenderableVolumeCL: public RenderableVolume { -public: - - // constructors & destructor - RenderableVolumeCL(const ghoul::Dictionary& dictionary); - ~RenderableVolumeCL(); - - bool initialize(); - bool deinitialize(); - - virtual void render(const Camera *camera, const psc& thisPosition); - virtual void update(); - -private: - - void safeKernelCompilation(); - - std::string _filename; - ghoul::RawVolumeReader::ReadHints _hints; - float _stepSize; - ghoul::opengl::FramebufferObject* _fbo; - ghoul::opengl::Texture* _backTexture; - ghoul::opengl::Texture* _frontTexture; - ghoul::opengl::Texture* _volume; - ghoul::opengl::Texture* _output; - ghoul::opengl::ProgramObject *_fboProgram; - ghoul::opengl::ProgramObject *_quadProgram; - sgct_utils::SGCTBox* _boundingBox; - GLuint _screenQuad; - - ghoul::opencl::CLContext _context; - ghoul::opencl::CLCommandQueue _commands; - ghoul::opencl::CLProgram _program; - ghoul::opencl::CLKernel _kernel; - ghoul::opencl::CLWorkSize* _ws; - cl_mem _clBackTexture, _clFrontTexture, _clVolume, _clOutput; - - ghoul::filesystem::File* _kernelSourceFile; - bool _kernelUpdateOnSave; - std::mutex* _kernelMutex; - -}; - -} // namespace openspace - -#endif \ No newline at end of file +// This is still in the repository to be cannibalized for a possible rewrite (ab) +///***************************************************************************************** +// * * +// * OpenSpace * +// * * +// * Copyright (c) 2014 * +// * * +// * Permission is hereby granted, free of charge, to any person obtaining a copy of this * +// * software and associated documentation files (the "Software"), to deal in the Software * +// * without restriction, including without limitation the rights to use, copy, modify, * +// * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +// * permit persons to whom the Software is furnished to do so, subject to the following * +// * conditions: * +// * * +// * The above copyright notice and this permission notice shall be included in all copies * +// * or substantial portions of the Software. * +// * * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +// * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +// * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +// * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +// * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +// * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +// ****************************************************************************************/ +// +//#ifndef __RENDERABLEVOLUMECL_H__ +//#define __RENDERABLEVOLUMECL_H__ +// +//// open space includes +//#include +// +//// ghoul includes +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +// +//#define SGCT_WINDOWS_INCLUDE +//#include +// +//namespace sgct_utils { +// class SGCTBox; +//} +// +////#include +////#include +//#ifdef __APPLE__ +// #include +//#else +// #include +//#endif +// +//namespace openspace { +// +//class RenderableVolumeCL: public RenderableVolume { +//public: +// +// // constructors & destructor +// RenderableVolumeCL(const ghoul::Dictionary& dictionary); +// ~RenderableVolumeCL(); +// +// bool initialize(); +// bool deinitialize(); +// +// virtual void render(const Camera *camera, const psc& thisPosition); +// virtual void update(); +// +//private: +// +// void safeKernelCompilation(); +// +// std::string _filename; +// ghoul::RawVolumeReader::ReadHints _hints; +// float _stepSize; +// ghoul::opengl::FramebufferObject* _fbo; +// ghoul::opengl::Texture* _backTexture; +// ghoul::opengl::Texture* _frontTexture; +// ghoul::opengl::Texture* _volume; +// ghoul::opengl::Texture* _output; +// ghoul::opengl::ProgramObject *_fboProgram; +// ghoul::opengl::ProgramObject *_quadProgram; +// sgct_utils::SGCTBox* _boundingBox; +// GLuint _screenQuad; +// +// ghoul::opencl::CLContext _context; +// ghoul::opencl::CLCommandQueue _commands; +// ghoul::opencl::CLProgram _program; +// ghoul::opencl::CLKernel _kernel; +// ghoul::opencl::CLWorkSize* _ws; +// cl_mem _clBackTexture, _clFrontTexture, _clVolume, _clOutput; +// +// ghoul::filesystem::File* _kernelSourceFile; +// bool _kernelUpdateOnSave; +// std::mutex* _kernelMutex; +// +//}; +// +//} // namespace openspace +// +//#endif \ No newline at end of file diff --git a/include/openspace/rendering/renderablevolumeexpert.h b/include/openspace/rendering/renderablevolumeexpert.h index 5d445a8abb..90f50ccbbd 100644 --- a/include/openspace/rendering/renderablevolumeexpert.h +++ b/include/openspace/rendering/renderablevolumeexpert.h @@ -1,118 +1,119 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __RENDERABLEVOLUMEEXPERT_H__ -#define __RENDERABLEVOLUMEEXPERT_H__ - -// open space includes -#include -#include - -// ghoul includes -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __APPLE__ - #include -#else - #include -#endif - -namespace ghoul { - namespace opencl { - class CLWorkSize; - } -} - -namespace openspace { - -class RenderableVolumeExpert: public RenderableVolume { -public: - - // constructors & destructor - RenderableVolumeExpert(const ghoul::Dictionary& dictionary); - ~RenderableVolumeExpert(); - - bool initialize(); - bool deinitialize(); - - virtual void render(const Camera *camera, const psc& thisPosition); - virtual void update(); - -private: - - // private methods - void safeKernelCompilation(); - void safeUpdateTexture(const ghoul::filesystem::File& file); - - // Volumes - std::vector _volumePaths; - std::vector _volumeHints; - - // Textures - ghoul::opengl::Texture* _output; - std::vector _volumes; - std::vector _transferFunctions; - std::vector _transferFunctionsFiles; - - // opencl texture memory pointers - cl_mem _clBackTexture; - cl_mem _clFrontTexture; - cl_mem _clOutput; - std::vector _clVolumes; - std::vector _clTransferFunctions; - - // opencl program - ghoul::opencl::CLContext _context; - ghoul::opencl::CLCommandQueue _commands; - ghoul::opencl::CLProgram _program; - ghoul::opencl::CLKernel _kernel; - ghoul::opencl::CLWorkSize* _ws; - ghoul::filesystem::File* _kernelSourceFile; - std::vector > _kernelOptions; - std::vector _kernelIncludes; - std::vector > _kernelDefinitions; - bool _programUpdateOnSave; - - // mutexes to prevent inconsistencies - std::mutex* _kernelLock; - std::mutex* _textureLock; - - ghoul::opengl::ProgramObject *_quadProgram; - GLuint _screenQuad; - - VolumeRaycasterBox* _colorBoxRenderer; - glm::vec3 _boxScaling; - -}; - -} // namespace openspace - -#endif \ No newline at end of file +// This is still in the repository to be cannibalized for a possible rewrite (ab) +///***************************************************************************************** +// * * +// * OpenSpace * +// * * +// * Copyright (c) 2014 * +// * * +// * Permission is hereby granted, free of charge, to any person obtaining a copy of this * +// * software and associated documentation files (the "Software"), to deal in the Software * +// * without restriction, including without limitation the rights to use, copy, modify, * +// * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +// * permit persons to whom the Software is furnished to do so, subject to the following * +// * conditions: * +// * * +// * The above copyright notice and this permission notice shall be included in all copies * +// * or substantial portions of the Software. * +// * * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +// * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +// * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +// * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +// * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +// * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +// ****************************************************************************************/ +// +//#ifndef __RENDERABLEVOLUMEEXPERT_H__ +//#define __RENDERABLEVOLUMEEXPERT_H__ +// +//// open space includes +//#include +//#include +// +//// ghoul includes +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +// +//#ifdef __APPLE__ +// #include +//#else +// #include +//#endif +// +//namespace ghoul { +// namespace opencl { +// class CLWorkSize; +// } +//} +// +//namespace openspace { +// +//class RenderableVolumeExpert: public RenderableVolume { +//public: +// +// // constructors & destructor +// RenderableVolumeExpert(const ghoul::Dictionary& dictionary); +// ~RenderableVolumeExpert(); +// +// bool initialize(); +// bool deinitialize(); +// +// virtual void render(const Camera *camera, const psc& thisPosition); +// virtual void update(); +// +//private: +// +// // private methods +// void safeKernelCompilation(); +// void safeUpdateTexture(const ghoul::filesystem::File& file); +// +// // Volumes +// std::vector _volumePaths; +// std::vector _volumeHints; +// +// // Textures +// ghoul::opengl::Texture* _output; +// std::vector _volumes; +// std::vector _transferFunctions; +// std::vector _transferFunctionsFiles; +// +// // opencl texture memory pointers +// cl_mem _clBackTexture; +// cl_mem _clFrontTexture; +// cl_mem _clOutput; +// std::vector _clVolumes; +// std::vector _clTransferFunctions; +// +// // opencl program +// ghoul::opencl::CLContext _context; +// ghoul::opencl::CLCommandQueue _commands; +// ghoul::opencl::CLProgram _program; +// ghoul::opencl::CLKernel _kernel; +// ghoul::opencl::CLWorkSize* _ws; +// ghoul::filesystem::File* _kernelSourceFile; +// std::vector > _kernelOptions; +// std::vector _kernelIncludes; +// std::vector > _kernelDefinitions; +// bool _programUpdateOnSave; +// +// // mutexes to prevent inconsistencies +// std::mutex* _kernelLock; +// std::mutex* _textureLock; +// +// ghoul::opengl::ProgramObject *_quadProgram; +// GLuint _screenQuad; +// +// VolumeRaycasterBox* _colorBoxRenderer; +// glm::vec3 _boxScaling; +// +//}; +// +//} // namespace openspace +// +//#endif \ No newline at end of file diff --git a/include/openspace/rendering/renderablevolumegl.h b/include/openspace/rendering/renderablevolumegl.h index 6cca3f458f..4706078bfd 100644 --- a/include/openspace/rendering/renderablevolumegl.h +++ b/include/openspace/rendering/renderablevolumegl.h @@ -25,7 +25,6 @@ #ifndef __RENDERABLEVOLUMEGL_H__ #define __RENDERABLEVOLUMEGL_H__ -// open space includes #include // ghoul includes @@ -35,25 +34,10 @@ #include #include -#define SGCT_WINDOWS_INCLUDE -#include - -#ifdef __APPLE__ - #include -#else - #include -#endif - -namespace sgct_utils { - class SGCTBox; -} - namespace openspace { class RenderableVolumeGL: public RenderableVolume { public: - - // constructors & destructor RenderableVolumeGL(const ghoul::Dictionary& dictionary); ~RenderableVolumeGL(); @@ -64,29 +48,31 @@ public: virtual void update(); private: - - + ghoul::Dictionary _hintsDictionary; + std::string _filename; - ghoul::RawVolumeReader::ReadHints _hints; - float _stepSize; - ghoul::opengl::FramebufferObject* _fbo; - ghoul::opengl::Texture* _backTexture; - ghoul::opengl::Texture* _frontTexture; + + std::string _transferFunctionName; + std::string _volumeName; + + std::string _transferFunctionPath; + std::string _samplerFilename; + + ghoul::filesystem::File* _transferFunctionFile; + ghoul::opengl::Texture* _volume; - ghoul::opengl::ProgramObject *_fboProgram, *_twopassProgram; - sgct_utils::SGCTBox* _boundingBox; - GLuint _screenQuad; - - std::mutex* _shaderMutex; - - ghoul::filesystem::File* _vertexSourceFile; - ghoul::filesystem::File* _fragmentSourceFile; - bool _programUpdateOnSave; - - void safeShaderCompilation(); + ghoul::opengl::Texture* _transferFunction; + + GLuint _boxArray; + ghoul::opengl::ProgramObject *_boxProgram; + glm::vec3 _boxScaling, _boxOffset; + float _w; + GLint _MVPLocation, _modelTransformLocation, _typeLocation; + bool _updateTransferfunction; + int _id; }; } // namespace openspace -#endif \ No newline at end of file +#endif diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index da2c74d712..2c64e84e5b 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -30,6 +30,8 @@ #include #include +#include + namespace openspace { class Camera; @@ -45,6 +47,7 @@ public: SceneGraph* sceneGraph(); Camera* camera() const; + ABuffer* abuffer() const; // sgct wrapped functions bool initializeGL(); @@ -58,6 +61,8 @@ public: private: Camera* _mainCamera; SceneGraph* _sceneGraph; + + ABuffer* _abuffer; }; } // namespace openspace diff --git a/include/openspace/rendering/volumeraycasterbox.h b/include/openspace/rendering/volumeraycasterbox.h index 5792b0e0c3..4e0a3018d5 100644 --- a/include/openspace/rendering/volumeraycasterbox.h +++ b/include/openspace/rendering/volumeraycasterbox.h @@ -45,7 +45,7 @@ public: VolumeRaycasterBox(); ~VolumeRaycasterBox(); bool initialize(); - void render(const glm::mat4& MVP); + void render(const glm::mat4& MVP, const glm::mat4& transform = glm::mat4(1.0), int type = 0); ghoul::opengl::Texture* backFace(); ghoul::opengl::Texture* frontFace(); @@ -56,7 +56,7 @@ private: ghoul::opengl::Texture *_backTexture, *_frontTexture; ghoul::opengl::ProgramObject *_boxProgram; sgct_utils::SGCTBox* _boundingBox; - GLint _MVPLocation; + GLint _MVPLocation, _modelTransformLocation, _typeLocation; glm::size2_t _dimensions; }; diff --git a/include/openspace/scenegraph/ephemeris.h b/include/openspace/scenegraph/ephemeris.h index c73b14e692..b8e13e8b8d 100644 --- a/include/openspace/scenegraph/ephemeris.h +++ b/include/openspace/scenegraph/ephemeris.h @@ -36,9 +36,9 @@ public: Ephemeris(const ghoul::Dictionary& dictionary); virtual ~Ephemeris(); - virtual bool initialize() = 0; + virtual bool initialize(); virtual const psc& position() const = 0; - virtual void update() = 0; + virtual void update(); protected: Ephemeris(); diff --git a/include/openspace/scenegraph/scenegraph.h b/include/openspace/scenegraph/scenegraph.h index 56249fe426..59e6e2b08e 100644 --- a/include/openspace/scenegraph/scenegraph.h +++ b/include/openspace/scenegraph/scenegraph.h @@ -22,8 +22,8 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef SCENEGRAPH_H -#define SCENEGRAPH_H +#ifndef __SCENEGRAPH_H__ +#define __SCENEGRAPH_H__ // std includes #include @@ -31,12 +31,15 @@ #include +#include + // ghoul includes #include #include namespace openspace { + class SceneGraphNode; class SceneGraph { @@ -94,6 +97,16 @@ public: */ SceneGraphNode* sceneGraphNode(const std::string& name) const; + /** + * Returns the Lua library that contains all Lua functions available to change the + * scene graph. The functions contained are + * - openspace::luascriptfunctions::property_setValue + * - openspace::luascriptfunctions::property_getValue + * \return The Lua library that contains all Lua functions available to change the + * scene graph + */ + static scripting::ScriptEngine::LuaLibrary luaLibrary(); + private: std::string _focus, _position; @@ -105,4 +118,4 @@ private: } // namespace openspace -#endif \ No newline at end of file +#endif // __SCENEGRAPH_H__ \ No newline at end of file diff --git a/include/openspace/scenegraph/scenegraphnode.h b/include/openspace/scenegraph/scenegraphnode.h index 2269d7d7cf..a7cf2089b7 100644 --- a/include/openspace/scenegraph/scenegraphnode.h +++ b/include/openspace/scenegraph/scenegraphnode.h @@ -22,12 +22,13 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef SCENEGRAPHNODE_H -#define SCENEGRAPHNODE_H +#ifndef __SCENEGRAPHNODE_H__ +#define __SCENEGRAPHNODE_H__ // open space includes #include #include +#include #include #include @@ -40,8 +41,10 @@ namespace openspace { -class SceneGraphNode { +class SceneGraphNode : public properties::PropertyOwner { public: + static std::string RootNodeName; + // constructors & destructor SceneGraphNode(); ~SceneGraphNode(); @@ -59,31 +62,30 @@ public: // set & get void addNode(SceneGraphNode* child); - void setName(const std::string& name); void setParent(SceneGraphNode* parent); - const psc& getPosition() const; - psc getWorldPosition() const; - std::string nodeName() const; + const psc& position() const; + psc worldPosition() const; SceneGraphNode* parent() const; const std::vector& children() const; // bounding sphere PowerScaledScalar calculateBoundingSphere(); + PowerScaledScalar boundingSphere() const; - SceneGraphNode* get(const std::string& name); + SceneGraphNode* childNode(const std::string& name); void print() const; // renderable void setRenderable(Renderable* renderable); - const Renderable* getRenderable() const; + const Renderable* renderable() const; + Renderable* renderable(); private: // essential std::vector _children; SceneGraphNode* _parent; - std::string _nodeName; Ephemeris* _ephemeris; // renderable @@ -100,4 +102,4 @@ private: } // namespace openspace -#endif +#endif // __SCENEGRAPHNODE_H__ diff --git a/include/openspace/scenegraph/spiceephemeris.h b/include/openspace/scenegraph/spiceephemeris.h index 70c404e10c..3229b09428 100644 --- a/include/openspace/scenegraph/spiceephemeris.h +++ b/include/openspace/scenegraph/spiceephemeris.h @@ -31,20 +31,20 @@ namespace openspace { -class SpiceEphemeris: public Ephemeris { +class SpiceEphemeris : public Ephemeris { public: SpiceEphemeris(const ghoul::Dictionary& dictionary); virtual ~SpiceEphemeris(); virtual bool initialize(); virtual const psc& position() const; virtual void update(); -protected: -private: - std::string _targetName, _originName; - int _target, _origin; +private: + std::string _targetName; + std::string _originName; + int _target; + int _origin; psc _position; - }; } // namespace openspace diff --git a/include/openspace/scenegraph/staticephemeris.h b/include/openspace/scenegraph/staticephemeris.h index e5d8001db8..71b5d02a5b 100644 --- a/include/openspace/scenegraph/staticephemeris.h +++ b/include/openspace/scenegraph/staticephemeris.h @@ -33,14 +33,11 @@ class StaticEphemeris: public Ephemeris { public: StaticEphemeris(const ghoul::Dictionary& dictionary = ghoul::Dictionary()); - virtual ~StaticEphemeris(); - virtual bool initialize(); - virtual const psc& position() const; - virtual void update(); -protected: + ~StaticEphemeris(); + const psc& position() const; + private: psc _position; - }; } // namespace openspace diff --git a/include/openspace/scripting/scriptengine.h b/include/openspace/scripting/scriptengine.h new file mode 100644 index 0000000000..648bc0ca12 --- /dev/null +++ b/include/openspace/scripting/scriptengine.h @@ -0,0 +1,77 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __SCRIPTENGINE_H__ +#define __SCRIPTENGINE_H__ + +#include +#include + +/** + * \defgroup LuaScripts Lua Scripts + */ + +namespace openspace { +namespace scripting { + +class ScriptEngine { +public: + struct LuaLibrary { + struct Function { + std::string name; + lua_CFunction function; + std::string helpText; + }; + std::string name; + std::vector functions; + + bool operator<(const LuaLibrary& rhs) const; + }; + + ScriptEngine(); + + bool initialize(); + void deinitialize(); + + bool addLibrary(const LuaLibrary& library); + bool hasLibrary(const std::string& name); + + bool runScript(const std::string& script); + bool runScriptFile(const std::string& filename); + +private: + bool isLibraryNameAllowed(const std::string& name); + void addLibraryFunctions(const LuaLibrary& library, bool replace); + + void addBaseLibrary(); + void remapPrintFunction(); + + lua_State* _state; + std::set _registeredLibraries; +}; + +} // namespace scripting +} // namespace openspace + +#endif // __SCRIPTENGINE_H__ diff --git a/include/openspace/tests/test_luaconversions.inl b/include/openspace/tests/test_luaconversions.inl new file mode 100644 index 0000000000..53cbd368f5 --- /dev/null +++ b/include/openspace/tests/test_luaconversions.inl @@ -0,0 +1,151 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "gtest/gtest.h" + +#include +#include +#include +#include +#include +#include + +class LuaConversionTest : public testing::Test { +protected: + lua_State* state; + + LuaConversionTest() { + state = luaL_newstate(); + luaL_openlibs(state); + } + + ~LuaConversionTest() { + lua_close(state); + } + + void reset() { + lua_close(state); + state = luaL_newstate(); + luaL_openlibs(state); + } +}; + +TEST_F(LuaConversionTest, LuaExecution) { + int status = luaL_loadstring(state, ""); + EXPECT_EQ(status, LUA_OK); +} + +#define CONVERSION_TEST_TEMPLATE(__NAME__, __TYPE__, __VALUE__) \ + TEST_F(LuaConversionTest, __NAME__) \ + { \ + using namespace openspace::properties; \ + bool success \ + = PropertyDelegate>::toLuaValue<__TYPE__>( \ + state, __VALUE__); \ + EXPECT_TRUE(success) << "toLuaValue"; \ + __TYPE__ value = (__TYPE__)(0); \ + value = PropertyDelegate>::fromLuaValue<__TYPE__>( \ + state, success); \ + EXPECT_TRUE(success) << "fromLuaValue"; \ + EXPECT_EQ(value, __VALUE__) << "fromLuaValue"; \ + } + +#define CONVERSION_TEST_NUMERICAL(__NAME__, __TYPE__, __VALUE__) \ + TEST_F(LuaConversionTest, __NAME__) \ + { \ + using namespace openspace::properties; \ + bool success \ + = PropertyDelegate>::toLuaValue<__TYPE__>( \ + state, __VALUE__); \ + EXPECT_TRUE(success) << "toLuaValue"; \ + __TYPE__ value = (__TYPE__)(0); \ + value = PropertyDelegate>::fromLuaValue<__TYPE__>( \ + state, success); \ + EXPECT_TRUE(success) << "fromLuaValue"; \ + EXPECT_EQ(value, __VALUE__) << "fromLuaValue"; \ + } + +CONVERSION_TEST_TEMPLATE(Bool, bool, true); + +CONVERSION_TEST_NUMERICAL(Char, char, 1); +CONVERSION_TEST_NUMERICAL(WChar, wchar_t, 1); +CONVERSION_TEST_NUMERICAL(SignedChar, signed char, 1); +CONVERSION_TEST_NUMERICAL(UnsignedChar, unsigned char, 1); +CONVERSION_TEST_NUMERICAL(Short, short, 1); +CONVERSION_TEST_NUMERICAL(UnsignedShort, unsigned short, 1); +CONVERSION_TEST_NUMERICAL(Int, int, 1); +CONVERSION_TEST_NUMERICAL(UnsignedInt, unsigned int, 1); +CONVERSION_TEST_NUMERICAL(Long, long, 1); +CONVERSION_TEST_NUMERICAL(UnsignedLong, unsigned long, 1); +CONVERSION_TEST_NUMERICAL(LongLong, long long, 1); +CONVERSION_TEST_NUMERICAL(UnsignedLongLong, unsigned long long, 1); +CONVERSION_TEST_NUMERICAL(Float, float, 1.f); +CONVERSION_TEST_NUMERICAL(Double, double, 1.0); +CONVERSION_TEST_NUMERICAL(LongDouble, long double, 1.0); + +CONVERSION_TEST_NUMERICAL(Vec2, glm::vec2, glm::vec2(1.f)); +CONVERSION_TEST_NUMERICAL(Vec3, glm::vec3, glm::vec3(1.f)); +CONVERSION_TEST_NUMERICAL(Vec4, glm::vec4, glm::vec4(1.f)); +CONVERSION_TEST_NUMERICAL(DVec2, glm::dvec2, glm::dvec2(1.0)); +CONVERSION_TEST_NUMERICAL(DVec3, glm::dvec3, glm::dvec3(1.0)); +CONVERSION_TEST_NUMERICAL(DVec4, glm::dvec4, glm::dvec4(1.0)); +CONVERSION_TEST_NUMERICAL(IVec2, glm::ivec2, glm::ivec2(1)); +CONVERSION_TEST_NUMERICAL(IVec3, glm::ivec3, glm::ivec3(1)); +CONVERSION_TEST_NUMERICAL(IVec4, glm::ivec4, glm::ivec4(1)); +CONVERSION_TEST_NUMERICAL(UVec2, glm::uvec2, glm::uvec2(1)); +CONVERSION_TEST_NUMERICAL(UVec3, glm::uvec3, glm::uvec3(1)); +CONVERSION_TEST_NUMERICAL(UVec4, glm::uvec4, glm::uvec4(1)); + +CONVERSION_TEST_NUMERICAL(Mat2x2, glm::mat2x2, glm::mat2x2(1.f)); +CONVERSION_TEST_NUMERICAL(Mat2x3, glm::mat2x3, glm::mat2x3(1.f)); +CONVERSION_TEST_NUMERICAL(Mat2x4, glm::mat2x4, glm::mat2x4(1.f)); +CONVERSION_TEST_NUMERICAL(Mat3x2, glm::mat3x2, glm::mat3x2(1.f)); +CONVERSION_TEST_NUMERICAL(Mat3x3, glm::mat3x3, glm::mat3x3(1.f)); +CONVERSION_TEST_NUMERICAL(Mat3x4, glm::mat3x4, glm::mat3x4(1.f)); +CONVERSION_TEST_NUMERICAL(Mat4x2, glm::mat4x2, glm::mat4x2(1.f)); +CONVERSION_TEST_NUMERICAL(Mat4x3, glm::mat4x3, glm::mat4x3(1.f)); +CONVERSION_TEST_NUMERICAL(Mat4x4, glm::mat4x4, glm::mat4x4(1.f)); +CONVERSION_TEST_NUMERICAL(DMat2x2, glm::dmat2x2, glm::dmat2x2(1.f)); +CONVERSION_TEST_NUMERICAL(DMat2x3, glm::dmat2x3, glm::dmat2x3(1.f)); +CONVERSION_TEST_NUMERICAL(DMat2x4, glm::dmat2x4, glm::dmat2x4(1.f)); +CONVERSION_TEST_NUMERICAL(DMat3x2, glm::dmat3x2, glm::dmat3x2(1.f)); +CONVERSION_TEST_NUMERICAL(DMat3x3, glm::dmat3x3, glm::dmat3x3(1.f)); +CONVERSION_TEST_NUMERICAL(DMat3x4, glm::dmat3x4, glm::dmat3x4(1.f)); +CONVERSION_TEST_NUMERICAL(DMat4x2, glm::dmat4x2, glm::dmat4x2(1.f)); +CONVERSION_TEST_NUMERICAL(DMat4x3, glm::dmat4x3, glm::dmat4x3(1.f)); +CONVERSION_TEST_NUMERICAL(DMat4x4, glm::dmat4x4, glm::dmat4x4(1.f)); + +TEST_F(LuaConversionTest, String) +{ + using namespace openspace::properties; + bool success + = PropertyDelegate>::toLuaValue( + state, "value"); + EXPECT_TRUE(success) << "toLuaValue"; + std::string value = ""; + value = PropertyDelegate>::fromLuaValue( + state, success); + EXPECT_TRUE(success) << "fromLuaValue"; + EXPECT_EQ(value, "value") << "fromLuaValue"; +} \ No newline at end of file diff --git a/include/openspace/tests/test_powerscalecoordinates.inl b/include/openspace/tests/test_powerscalecoordinates.inl index ce500fe3b1..294cb139bb 100644 --- a/include/openspace/tests/test_powerscalecoordinates.inl +++ b/include/openspace/tests/test_powerscalecoordinates.inl @@ -1,9 +1,8 @@ /***************************************************************************************** * * - * GHOUL * - * General Helpful Open Utility Library * + * OpenSpace * * * - * Copyright (c) 2012-2014 * + * Copyright (c) 2014 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -25,6 +24,8 @@ #include "gtest/gtest.h" +#include + #include #include @@ -45,10 +46,10 @@ protected: TEST_F(PowerscaleCoordinatesTest, psc) { - openspace::psc reference(2.0, 1.0, 1.1, 1.0); + openspace::psc reference(2.f, 1.f, 1.1f, 1.f); - openspace::psc first(1.0,0.0,1.0,0.0); - openspace::psc second(1.9,1.0,1.0,1.0); + openspace::psc first(1.f, 0.f, 1.f, 0.f); + openspace::psc second(1.9f, 1.f, 1.f, 1.f); EXPECT_EQ(reference, first + second); EXPECT_TRUE(reference == (first + second)); @@ -63,10 +64,10 @@ TEST_F(PowerscaleCoordinatesTest, psc) { TEST_F(PowerscaleCoordinatesTest, pss) { - openspace::pss first(1.0,1.0); - openspace::pss second(1.0,-1.0); - EXPECT_EQ(openspace::pss(1.01,1.0), first + second); - EXPECT_EQ(openspace::pss(1.01,1.0), second + first); + openspace::pss first(1.f, 1.f); + openspace::pss second(1.f, -1.f); + EXPECT_EQ(openspace::pss(1.01f, 1.f), first + second); + EXPECT_EQ(openspace::pss(1.01f, 1.f), second + first); /* EXPECT_TRUE(first < (first + second)); bool retu =(second < (first + second)); diff --git a/include/openspace/tests/test_scenegraph.inl b/include/openspace/tests/test_scenegraph.inl index daef846cd0..91d2293a4e 100644 --- a/include/openspace/tests/test_scenegraph.inl +++ b/include/openspace/tests/test_scenegraph.inl @@ -1,9 +1,8 @@ /***************************************************************************************** * * - * GHOUL * - * General Helpful Open Utility Library * + * OpenSpace * * * - * Copyright (c) 2012-2014 * + * Copyright (c) 2014 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -55,8 +54,8 @@ TEST_F(SceneGraphTest, SceneGraphNode) { openspace::SceneGraphNode::createFromDictionary(ghoul::Dictionary()); // Should not have a renderable and position should be 0,0,0,0 (undefined). - EXPECT_EQ(nullptr, node->getRenderable()); - EXPECT_EQ(openspace::psc(), node->getPosition()); + EXPECT_EQ(nullptr, node->renderable()); + EXPECT_EQ(openspace::psc(), node->position()); delete node; ghoul::Dictionary nodeDictionary; @@ -83,10 +82,10 @@ TEST_F(SceneGraphTest, SceneGraphNode) { openspace::SceneGraphNode::createFromDictionary(nodeDictionary); // This node should have a renderable (probably no good values but an existing one) - EXPECT_TRUE(node->getRenderable()); + EXPECT_TRUE(node->renderable()); // position should be initialized - EXPECT_EQ(openspace::psc(1.0,1.0,1.0,1.0), node->getPosition()); + EXPECT_EQ(openspace::psc(1.0,1.0,1.0,1.0), node->position()); delete node; } diff --git a/include/openspace/tests/test_spicemanager.inl b/include/openspace/tests/test_spicemanager.inl index 24e62103fc..ab69468cbd 100644 --- a/include/openspace/tests/test_spicemanager.inl +++ b/include/openspace/tests/test_spicemanager.inl @@ -1,27 +1,27 @@ /***************************************************************************************** -* * -* GHOUL * -* General Helpful Open Utility Library * -* * -* Copyright (c) 2012-2014 * -* * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this * -* software and associated documentation files (the "Software"), to deal in the Software * -* without restriction, including without limitation the rights to use, copy, modify, * -* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -* permit persons to whom the Software is furnished to do so, subject to the following * -* conditions: * -* * -* The above copyright notice and this permission notice shall be included in all copies * -* or substantial portions of the Software. * -* * -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -****************************************************************************************/ + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #include #include "gtest/gtest.h" #include "openspace/util/spicemanager.h" @@ -49,7 +49,6 @@ protected: const int nrMetaKernels = 9; int which, handle, count = 0; char file[FILLEN], filtyp[TYPLEN], source[SRCLEN]; -int found; double abs_error = 0.00001; @@ -77,9 +76,10 @@ std::string fileType(char type[]){ TEST_F(SpiceManagerTest, loadSingleKernel){ loadLSKKernel(); //naif0008.tls is a text file, check if loaded. + SpiceBoolean found; kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - ASSERT_TRUE(found) << "Kernel not loaded"; + ASSERT_TRUE(found == SPICETRUE) << "Kernel not loaded"; unload_c(LSK.c_str()); } @@ -93,6 +93,7 @@ TEST_F(SpiceManagerTest, loadMetaKernel){ "TEXT", "CK", "TEXT" }; // If one of the kernels does not load we expect a mismatch for (int i = 0; i < nrMetaKernels; i++){ + SpiceBoolean found; kdata_c(i, "all", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); EXPECT_EQ(fileType(filtyp), typeArr[i]) << "One or more kernels did not load properly"; } @@ -102,29 +103,33 @@ TEST_F(SpiceManagerTest, loadMetaKernel){ TEST_F(SpiceManagerTest, unloadKernelString){ loadLSKKernel(); //naif0008.tls is a text file, check if loaded. + SpiceBoolean found; kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - ASSERT_TRUE(found); + ASSERT_TRUE(found == SPICETRUE); //unload using string keyword bool unloaded = openspace::SpiceManager::ref().unloadKernel("LEAPSECONDS"); EXPECT_TRUE(unloaded); + found = SPICEFALSE; kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - EXPECT_FALSE(found); + EXPECT_FALSE(found == SPICETRUE); } // Try unloading kernel using integer as ID TEST_F(SpiceManagerTest, unloadKernelInteger){ int kernelID = loadLSKKernel(); //naif0008.tls is a text file, check if loaded. + SpiceBoolean found; kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - ASSERT_TRUE(found); + ASSERT_TRUE(found == SPICETRUE); //unload using unique int ID bool unloaded = openspace::SpiceManager::ref().unloadKernel(kernelID); EXPECT_TRUE(unloaded) << "Kernel did not unload"; + found = SPICEFALSE; kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - EXPECT_FALSE(found) << "One or more kernels still present in kernel-pool"; + EXPECT_FALSE(found == SPICETRUE) << "One or more kernels still present in kernel-pool"; } // Try unloading multiple kernels TEST_F(SpiceManagerTest, unloadMetaKernel){ @@ -136,6 +141,7 @@ TEST_F(SpiceManagerTest, unloadMetaKernel){ for (int i = 0; i < nrMetaKernels; i++){ // check kernelpool against typeArr + SpiceBoolean found; kdata_c(i, "all", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); EXPECT_EQ(fileType(filtyp), typeArr[i]) << "One or more kernels did not load properly"; } @@ -144,8 +150,9 @@ TEST_F(SpiceManagerTest, unloadMetaKernel){ for (int i = 0; i < nrMetaKernels; i++){ // the values should by now be unloaded + SpiceBoolean found; kdata_c(i, "all", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - EXPECT_FALSE(found) << "Failed unloading kernel"; + EXPECT_FALSE(found == SPICETRUE) << "Failed unloading kernel"; } unload_c(META.c_str()); } @@ -153,13 +160,11 @@ TEST_F(SpiceManagerTest, unloadMetaKernel){ TEST_F(SpiceManagerTest, hasValue){ loadPCKKernel(); - int n; int naifId = 399; //Earth - double radii[3]; std::string kernelPoolValue = "RADII"; - found = openspace::SpiceManager::ref().hasValue(naifId, kernelPoolValue); + bool found = openspace::SpiceManager::ref().hasValue(naifId, kernelPoolValue); ASSERT_TRUE(found) << "Could not find value for specified kernel"; unload_c(PCK.c_str()); } @@ -171,7 +176,7 @@ TEST_F(SpiceManagerTest, getValueFromID_1D){ std::string value1D = "MAG_NORTH_POLE_LAT"; double return1D; - found = openspace::SpiceManager::ref().getValueFromID(target, value1D, return1D); + bool found = openspace::SpiceManager::ref().getValueFromID(target, value1D, return1D); ASSERT_TRUE(found) << "Could not retrieve value"; EXPECT_EQ(return1D, 78.565) << "Value not found / differs from expected return"; unload_c(PCK.c_str()); @@ -200,14 +205,14 @@ TEST_F(SpiceManagerTest, getValueFromID_ND){ std::vector returnND; unsigned int nr = 5; - found = openspace::SpiceManager::ref().getValueFromID(target, valueND, returnND, nr); + bool found = openspace::SpiceManager::ref().getValueFromID(target, valueND, returnND, nr); ASSERT_TRUE(found) << "Could not retrieve value for specified kernel"; std::vector controlVec{ 189870.0, 256900.0, 9000.0, 9000.0, 0.000003 }; ASSERT_EQ(controlVec.size(), returnND.size()) << "Vectors differ in size"; - for (int i = 0; i < nr; i++){ + for (unsigned int i = 0; i < nr; ++i){ EXPECT_EQ(controlVec[i], returnND[i]) << "Vector value not equal"; } unload_c(PCK.c_str()); @@ -218,10 +223,10 @@ TEST_F(SpiceManagerTest, stringToEphemerisTime){ double ephemerisTime; double control_ephemerisTime; - char *date = "Thu Mar 20 12:53:29 PST 1997"; + char date[SRCLEN] = "Thu Mar 20 12:53:29 PST 1997"; str2et_c(date, &control_ephemerisTime); - ephemerisTime = openspace::SpiceManager::ref().stringToEphemerisTime(date); + ephemerisTime = openspace::SpiceManager::ref().convertStringToTdbSeconds(date); EXPECT_EQ(ephemerisTime, control_ephemerisTime) << "Ephemeries times differ / not found"; unload_c(LSK.c_str()); @@ -240,7 +245,7 @@ TEST_F(SpiceManagerTest, getTargetPosition){ glm::dvec3 targetPosition; double lightTime = 0.0; - found = openspace::SpiceManager::ref().getTargetPosition("EARTH", et, "J2000", "LT+S", "CASSINI", + bool found = openspace::SpiceManager::ref().getTargetPosition("EARTH", et, "J2000", "LT+S", "CASSINI", targetPosition, lightTime); ASSERT_TRUE(found); EXPECT_DOUBLE_EQ(pos[0], targetPosition[0]) << "Position not found or differs from expected return"; @@ -263,7 +268,7 @@ TEST_F(SpiceManagerTest, getTargetState){ glm::dvec3 targetPosition; glm::dvec3 targetVelocity; double lightTime = 0.0; - found = openspace::SpiceManager::ref().getTargetState("EARTH", et, "J2000", "LT+S", "CASSINI", + bool found = openspace::SpiceManager::ref().getTargetState("EARTH", et, "J2000", "LT+S", "CASSINI", targetPosition, targetVelocity, lightTime); ASSERT_TRUE(found); //x,y,z @@ -291,7 +296,7 @@ TEST_F(SpiceManagerTest, getStateTransformMatrix){ glm::dvec3 velocity(state[3], state[4], state[5]); openspace::transformMatrix stateMatrix(6); - found = openspace::SpiceManager::ref().getStateTransformMatrix("J2000", + bool found = openspace::SpiceManager::ref().getStateTransformMatrix("J2000", "IAU_PHOEBE", et, stateMatrix); @@ -317,7 +322,6 @@ TEST_F(SpiceManagerTest, getPositionTransformMatrix){ loadMetaKernel(); double et; - double lt; double state[3] = { 1.0, 1.0, 1.0 }; double state_t[3]; double referenceMatrix[3][3]; @@ -327,7 +331,7 @@ TEST_F(SpiceManagerTest, getPositionTransformMatrix){ openspace::transformMatrix positionMatrix(3); glm::dvec3 position(state[0], state[1], state[2]); - found = openspace::SpiceManager::ref().getPositionTransformMatrix("CASSINI_HGA", + bool found = openspace::SpiceManager::ref().getPositionTransformMatrix("CASSINI_HGA", "J2000", et, positionMatrix); @@ -355,17 +359,16 @@ TEST_F(SpiceManagerTest, getFieldOfView){ int n; int cassini_ID; double et; - double lt; double boresight[3]; double bounds_ref[5][3]; char shape_ref[TYPLEN]; char name_ref[FILLEN]; str2et_c("2004 jun 11 19:32:00", &et); + SpiceBoolean found; bodn2c_c("CASSINI_ISS_NAC", &cassini_ID, &found); - if (!found){ - printf("error cannot locate ID for Cassini \n"); - } + ASSERT_TRUE(found == SPICETRUE) << "Cannot locate ID for Cassini"; + getfov_c(cassini_ID, 5, TYPLEN, TYPLEN, shape_ref, name_ref, boresight, &n, bounds_ref); std::string shape, name; @@ -379,7 +382,7 @@ TEST_F(SpiceManagerTest, getFieldOfView){ boresight, bounds, nrReturned); - ASSERT_TRUE(found); + ASSERT_TRUE(found == SPICETRUE); //check vectors have correct values for (int i = 0; i < nrReturned; i++){ for (int j = 0; j < 3; j++){ @@ -399,14 +402,17 @@ TEST_F(SpiceManagerTest, rectangularToLatitudal){ obspos[3], point_ref[3]; double dist, et, radius_ref, trgepc; int n, naifId; - int found; + bool found; + SpiceBoolean foundSpice; // First, find an intersection point to convert to rectangular coordinates str2et_c("2004 jun 11 19:32:00", &et); - bodn2c_c("CASSINI_ISS_NAC", &naifId, &found); + bodn2c_c("CASSINI_ISS_NAC", &naifId, &foundSpice); + ASSERT_TRUE(foundSpice == SPICETRUE); getfov_c(naifId, 4, FILLEN, FILLEN, shape, frame, bsight, &n, bounds); srfxpt_c("Ellipsoid", "PHOEBE", et, "LT+S", "CASSINI", frame, bsight, - point_ref, &dist, &trgepc, obspos, &found); + point_ref, &dist, &trgepc, obspos, &foundSpice); + ASSERT_TRUE(foundSpice == SPICETRUE); reclat_c(point_ref, &radius_ref, &lon, &lat); glm::dvec3 point(point_ref[0], point_ref[1], point_ref[2]); @@ -429,13 +435,17 @@ TEST_F(SpiceManagerTest, latitudinalToRectangular){ obspos[3], point_ref[3]; double dist, et, radius_ref, trgepc; int n, naifId; + SpiceBoolean foundSpice; // First, find an intersection point to convert to latitudinal coordinates // str2et_c("2004 jun 11 19:32:00", &et); - bodn2c_c("CASSINI_ISS_NAC", &naifId, &found); + bodn2c_c("CASSINI_ISS_NAC", &naifId, &foundSpice); + ASSERT_TRUE(foundSpice == SPICETRUE); getfov_c(naifId, 4, FILLEN, FILLEN, shape, frame, bsight, &n, bounds); + foundSpice = SPICEFALSE; srfxpt_c("Ellipsoid", "PHOEBE", et, "LT+S", "CASSINI", frame, bsight, - point_ref, &dist, &trgepc, obspos, &found); + point_ref, &dist, &trgepc, obspos, &foundSpice); + ASSERT_TRUE(foundSpice == SPICETRUE); reclat_c(point_ref, &radius_ref, &lon, &lat); @@ -449,7 +459,7 @@ TEST_F(SpiceManagerTest, latitudinalToRectangular){ latrec_c(radius_ref, lon, lat, rectangular_ref); glm::dvec3 coordinates; - found = openspace::SpiceManager::ref().latidudinalToRectangular(radius_ref, lon, lat, coordinates); + bool found = openspace::SpiceManager::ref().latidudinalToRectangular(radius_ref, lon, lat, coordinates); ASSERT_TRUE(found); ASSERT_NEAR(lon_ref, lon, abs_error) << "longitude is not set / has incorrect values"; @@ -463,14 +473,16 @@ TEST_F(SpiceManagerTest, planetocentricToRectangular){ double lat = -35.0; //initial values double lon = 100.0; double rectangular_ref[3]; - double radius; int naifId; + SpiceBoolean foundSpice; - bodn2c_c("EARTH", &naifId, &found); + bodn2c_c("EARTH", &naifId, &foundSpice); + ASSERT_TRUE(foundSpice == SPICETRUE); srfrec_c(naifId, lon*rpd_c(), lat*rpd_c(), rectangular_ref); glm::dvec3 rectangular; - found = openspace::SpiceManager::ref().planetocentricToRectangular("EARTH", lon, lat, rectangular); + bool found = openspace::SpiceManager::ref().planetocentricToRectangular("EARTH", lon, lat, rectangular); + ASSERT_TRUE(found); for (int i = 0; i < 3; i++){ EXPECT_EQ(rectangular[i], rectangular_ref[i]) << "Rectangular coordinates differ from expected output"; @@ -481,8 +493,11 @@ TEST_F(SpiceManagerTest, planetocentricToRectangular){ TEST_F(SpiceManagerTest, getSubObserverPoint){ loadMetaKernel(); - double et, targetEt_ref, targetEt; - double radii[3], subObserverPoint_ref[3], vectorToSurfacePoint_ref[3]; + double et; + double targetEt_ref; + double targetEt; + double subObserverPoint_ref[3]; + double vectorToSurfacePoint_ref[3]; static SpiceChar * method[2] = { "Intercept: ellipsoid", "Near point: ellipsoid" }; str2et_c("2004 jun 11 19:32:00", &et); @@ -494,7 +509,7 @@ TEST_F(SpiceManagerTest, getSubObserverPoint){ subpnt_c(method[i], "phoebe", et, "iau_phoebe", "lt+s", "earth", subObserverPoint_ref, &targetEt_ref, vectorToSurfacePoint_ref); - found = openspace::SpiceManager::ref().getSubObserverPoint(method[i], "phoebe", et, "iau_phoebe", + bool found = openspace::SpiceManager::ref().getSubObserverPoint(method[i], "phoebe", et, "iau_phoebe", "lt+s", "earth", subObserverPoint, targetEt, vectorToSurfacePoint); ASSERT_TRUE(found); @@ -513,7 +528,8 @@ TEST_F(SpiceManagerTest, getSubSolarPoint){ loadMetaKernel(); double et, targetEt_ref, targetEt; - double radii[3], subSolarPoint_ref[3], vectorToSurfacePoint_ref[3]; + double subSolarPoint_ref[3]; + double vectorToSurfacePoint_ref[3]; static SpiceChar * method[2] = { "Intercept: ellipsoid", "Near point: ellipsoid" }; str2et_c("2004 jun 11 19:32:00", &et); @@ -525,7 +541,7 @@ TEST_F(SpiceManagerTest, getSubSolarPoint){ subslr_c(method[i], "phoebe", et, "iau_phoebe", "lt+s", "earth", subSolarPoint_ref, &targetEt_ref, vectorToSurfacePoint_ref); - found = openspace::SpiceManager::ref().getSubSolarPoint(method[i], "phoebe", et, "iau_phoebe", + bool found = openspace::SpiceManager::ref().getSubSolarPoint(method[i], "phoebe", et, "iau_phoebe", "lt+s", "earth", subSolarPoint, targetEt, vectorToSurfacePoint); ASSERT_TRUE(found); diff --git a/include/openspace/util/constants.h b/include/openspace/util/constants.h index f16ae7b57f..f862f7ce17 100644 --- a/include/openspace/util/constants.h +++ b/include/openspace/util/constants.h @@ -34,6 +34,8 @@ namespace openspaceengine { const std::string keyPathScene = "Paths.SCENEPATH"; const std::string keyConfigSgct = "SGCTConfig"; const std::string keyConfigScene = "Scene"; + const std::string keyStartupScript = "StartupScripts"; + const std::string keyConfigTimekernel = "SpiceTimeKernel"; } // namespace openspaceengine namespace scenegraph { @@ -64,16 +66,33 @@ namespace renderablestars { const std::string keyPathModule = "ModulePath"; } // namespace renderablestars +namespace renderablevolumegl { + const std::string keyVolume = "Volume"; + const std::string keyHints = "Hints"; + const std::string keyTransferFunction = "TransferFunction"; + const std::string keySampler = "Sampler"; + const std::string keyBoxScaling = "BoxScaling"; + const std::string keyVolumeName = "VolumeName"; + const std::string keyTransferFunctionName = "TransferFunctionName"; +} // namespace renderablevolumegl + namespace planetgeometry { const std::string keyType = "Type"; } // namespace planetgeometry - - namespace ephemeris { const std::string keyType = "Type"; } // namespace ephemeris +namespace staticephemeris { + const std::string keyPosition = "Position"; +} // namespace staticephemeris + +namespace spiceephemeris { + const std::string keyBody = "Body"; + const std::string keyOrigin = "Observer"; +} // namespace spiceephemeris + } // namespace constants } // namespace openspace diff --git a/include/openspace/util/kameleonwrapper.h b/include/openspace/util/kameleonwrapper.h index 3ba0afbbb0..1bd768e72a 100644 --- a/include/openspace/util/kameleonwrapper.h +++ b/include/openspace/util/kameleonwrapper.h @@ -25,7 +25,6 @@ #ifndef KAMELEONWRAPPER_H_ #define KAMELEONWRAPPER_H_ -#include #include namespace ccmc { @@ -35,6 +34,16 @@ namespace ccmc { namespace openspace { +struct LinePoint { + glm::vec3 position; + glm::vec4 color; + + LinePoint(glm::vec3 pos, glm::vec4 col) { + position = pos; + color = col; + } +}; + class KameleonWrapper { public: @@ -43,14 +52,58 @@ public: BATSRUS // Magnetosphere }; + enum class TraceDirection { + FORWARD = 1, + BACK = -1 + }; + + enum class FieldlineEnd { + NORTH, + SOUTH, + OUT + }; + KameleonWrapper(const std::string& filename, Model model); ~KameleonWrapper(); float* getUniformSampledValues(const std::string& var, glm::size3_t outDimensions); + float* getUniformSampledVectorValues(const std::string& xVar, const std::string& yVar, + const std::string& zVar, glm::size3_t outDimensions); + + std::vector > getClassifiedFieldLines(const std::string& xVar, + const std::string& yVar, const std::string& zVar, + std::vector seedPoints, float stepSize); + + std::vector > getFieldLines(const std::string& xVar, + const std::string& yVar, const std::string& zVar, + std::vector seedPoints, float stepSize, glm::vec4 color); + + std::vector > getLorentzTrajectories(std::vector seedPoints, + glm::vec4 color, float stepsize); + + glm::vec3 getModelBarycenterOffset(); private: + std::vector traceCartesianFieldline(const std::string& xVar, + const std::string& yVar, const std::string& zVar, glm::vec3 seedPoint, + float stepSize, TraceDirection direction, FieldlineEnd& end); + + std::vector traceLorentzTrajectory(glm::vec3 seedPoint, + float stepsize, float eCharge); + + void getGridVariables(std::string& x, std::string& y, std::string& z); + void progressBar(int current, int end); + glm::vec4 classifyFieldline(FieldlineEnd fEnd, FieldlineEnd bEnd); + ccmc::Model* _model; Model _type; ccmc::Interpolator* _interpolator; + + // Model parameters + float _xMin, _xMax, _yMin, _yMax, _zMin, _zMax; + std::string _xCoordVar, _yCoordVar, _zCoordVar; + + // For progressbar + int _lastiProgress; }; } // namespace openspace diff --git a/include/openspace/util/shadercreator.h b/include/openspace/util/shadercreator.h new file mode 100644 index 0000000000..61ddecf338 --- /dev/null +++ b/include/openspace/util/shadercreator.h @@ -0,0 +1,60 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __SHADERCREATOR_H__ +#define __SHADERCREATOR_H__ + + +#include + +#include + +namespace openspace { +class ShaderCreator { + +public: + ShaderCreator(); + ~ShaderCreator(); + + void createSourceFile(bool b); + void sourceFileExtension(const std::string& extension); + void sourceFileHeader(const std::string& header); + + ghoul::opengl::ProgramObject* buildShader(const std::string& name, const std::string& vpath, const std::string& fpath, const std::string& gpath = ""); + +private: + + void _generateSource(const std::string& filename); + std::string _loadSource(const std::string& filename, unsigned int depth = 0); + std::string _generateFilename(const std::string& filename); + + bool _createSourceFile; + std::string _sourceFileExtension; + std::string _sourceFileHeader; + unsigned int _maxDepth; + +}; +} + +#endif \ No newline at end of file diff --git a/include/openspace/util/spicemanager.h b/include/openspace/util/spicemanager.h index 7490e008c8..695dcd9dd1 100644 --- a/include/openspace/util/spicemanager.h +++ b/include/openspace/util/spicemanager.h @@ -92,19 +92,19 @@ public: * \param kernelPoolValueName Item for which values are desired. ("RADII", "NUT_PREC_ANGLES", etc. ) * \return Whether the function succeeded or not */ - bool SpiceManager::getValueFromID(const std::string& bodyname, + bool getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, double& value) const; /* Overloaded method for 3dim vectors, see above specification.*/ - bool SpiceManager::getValueFromID(const std::string& bodyname, + bool getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, glm::dvec3& value) const; /* Overloaded method for 4dim vectors, see above specification.*/ - bool SpiceManager::getValueFromID(const std::string& bodyname, + bool getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, glm::dvec4& value) const; /* Overloaded method for Ndim vectors, see above specification.*/ - bool SpiceManager::getValueFromID(const std::string& bodyname, + bool getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, std::vector& values, unsigned int num) const; @@ -119,7 +119,19 @@ public: * \param epochString, A string representing an epoch. * \return Corresponding ephemeris time, equivalent value in seconds past J2000, TDB. */ - double stringToEphemerisTime(const std::string& epochString) const; + double convertStringToTdbSeconds(const std::string& epochString) const; + + /** + * Convert the number of TDB seconds past the J2000 epoch into a human readable + * string representation. Fur further details, please refer to 'timout_c' in SPICE + * Documentation + * + * \param seconds The number of seconds that have passed since the J2000 epoch + * \param format The output format of the string + * (see ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/timout_c.html) + * \return The formatted date string + */ + std::string convertTdbSecondsToString(double seconds, const std::string& format) const; // Computing Positions of Spacecraft and Natural Bodies(SPK) ---------------------------- // @@ -337,7 +349,7 @@ private: struct spiceKernel { std::string path; std::string name; - int id; + unsigned int id; }; std::vector _loadedKernels; unsigned int _kernelCount = 0; @@ -382,6 +394,21 @@ public: data = new double[N*N]; empty = true; } + + void transform(glm::dvec3& position) { + assert(!empty); // transformation matrix is empty + + double *state; + double *state_t; + state = new double[N]; + state_t = new double[N]; + + COPY(state, &position); + mxvg_c(data, state, N, N, state_t); + + COPY(&position, state_t); + } + /** As the spice function mxvg_c requires a 6dim vector * the two 3dim state vectors are packed into 'state'. * Transformed values are then copied back from state_t @@ -394,8 +421,8 @@ public: * the method ignores its second argument. */ void transform(glm::dvec3& position, - glm::dvec3& velocity = glm::dvec3()){ - assert(("transformation matrix is empty", !empty)); + glm::dvec3& velocity) { + assert(!empty); // transformation matrix is empty double *state; double *state_t; @@ -414,7 +441,7 @@ public: * asserts matrix has been filled */ inline double operator()(int i, int j) const{ - assert(("transformation matrix is empty", !empty)); + assert(!empty); // transformation matrix is empty return data[j + i*N]; } }; diff --git a/include/openspace/util/time.h b/include/openspace/util/time.h index 84303a136c..2db604e328 100644 --- a/include/openspace/util/time.h +++ b/include/openspace/util/time.h @@ -1,31 +1,167 @@ -#ifndef ENGINETIME_H -#define ENGINETIME_H +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ -namespace openspace -{ +#ifndef __TIME_H__ +#define __TIME_H__ +#include +#include + +namespace openspace { + +/** + * This singleton class represents the current simulation time in OpenSpace. It + * internally stores the time and provides methods to set the time directly + * (setTime(double), setTime(std::string)) using a double value using the + * number of seconds passed since the J2000 epoch or a string that denotes + * a valid date string in accordance to the Spice library + * (http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/str2et_c.html). The time can + * be retrieved as the number of seconds since the J2000 epoch with currentTime() or as a + * UTC string following ISO 8601 with the method currentTimeUTC(). + * + * In addition to the time itself, it also stores a delta time value. This value denotes + * the number of seconds that pass for each real-time second. This value is set with + * setDeltaTime(double), retrieved with deltaTime() and solely used in the + * advanceTime(double), which takes a tickTime parameter. The value of the + * parameter is dependent on the usage of the class and must be equal to the real-world + * time that has passed since the last call to the method. For example, if the + * advanceTime(double) method is called each frame, the tickTime has to be + * equal to the frame time. + */ class Time { public: - virtual ~Time(); + /** + * Initializes the Time singleton and loads an LSK spice kernel with the provided + * name. + * \param lskKernel The name of the kernel that should be loaded during the + * initialization. If the parameter is empty, no kernel will be loaded + * \return true if the initialization succeeded, false + * otherwise + */ + static bool initialize(const std::string& lskKernel = ""); - static void init(); - static void deinit(); + /** + * Deinitializes the Time singleton. This method will not unload the kernel that was + * possibly loaded during the initialize method. + */ + static void deinitialize(); + + /** + * Returns the reference to the Time singleton object. + * \return The reference to the Time singleton object + */ static Time& ref(); - static bool isInitialized(); - void setTime(const char* stringTime); - double getTime(); + /** + * Returns true if the singleton has been successfully initialized, + * false otherwise + * \return true if the singleton has been successfully initialized, + * false otherwise + */ + static bool isInitialized(); + + /** + * Sets the current time to the specified value in seconds past the J2000 epoch. This + * value can be negative to represent dates before the epoch. + * \param The number of seconds after the J2000 epoch + */ + void setTime(double value); + + /** + * Sets the current time to the specified value given as a Spice compliant string as + * described in the Spice documentation + * (http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/str2et_c.html) + * \param time The time to be set as a date string + */ + void setTime(std::string time); + + /** + * Returns the current time as the number of seconds past the J2000 epoch. If the + * current time is a date before that epoch, the returned value will be negative. + * \return The current time as the number of seconds past the J2000 epoch + */ + double currentTime() const; + + /** + * Returns the current time as a formatted date string compliant with ISO 8601 and + * thus also compliant with the Spice library. + * \return The current time as a formatted date string + */ + std::string currentTimeUTC() const; + + /** + * Sets the delta time value that is the number of seconds that should pass for each + * real-time second. This value is used in the advanceTime(double) method to easily + * advance the simulation time. + * \param deltaT The number of seconds that should pass for each real-time second + */ + void setDeltaTime(double deltaT); + + /** + * Returns the delta time, that is the number of seconds that pass in the simulation + * for each real-time second + * \return The number of seconds that pass for each real-time second + */ + double deltaTime() const; + + /** + * Advances the simulation time using the deltaTime() and the tickTime. + * The deltaTime() is the number of simulation seconds that pass for each real-time + * second. tickTime is the number of real-time seconds that passed since + * the last call to this method. If this method is called in the render loop, the + * tickTime should be equivalent to the frame time. + * \param tickTime The number of real-time seconds that passed since the last call + * to this method + * \return The new time value after advancing the time + */ + double advanceTime(double tickTime); + + /** + * Returns the Lua library that contains all Lua functions available to change the + * current time, retrieve the current time etc. The functions contained are + * - openspace::luascriptfunctions::time_setDeltaTime + * - openspace::luascriptfunctions::time_deltaTime + * - openspace::luascriptfunctions::time_setTime + * - openspace::luascriptfunctions::time_currentTime + * - openspace::luascriptfunctions::time_currentTimeUTC + * \return The Lua library that contains all Lua functions available to change the + * Time singleton + */ + static scripting::ScriptEngine::LuaLibrary luaLibrary(); private: - static Time* this_; - Time(void); - Time(const Time& src); - Time& operator=(const Time& rhs); + /// Creates the time object. Only used in the initialize() method + Time(); + Time(const Time& src) = delete; + Time& operator=(const Time& rhs) = delete; - double time_; + static Time* _instance; ///< The singleton instance + double _time; ///< The time stored as the number of seconds past the J2000 epoch + + double _deltaTimePerSecond; ///< The delta time that is used to advance the time }; - } // namespace openspace -#endif \ No newline at end of file +#endif // __TIME_H__ diff --git a/openspace.cfg b/openspace.cfg index 4becaf05a8..a476eed479 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,10 +7,15 @@ return { OPENSPACE_DATA = "${BASE_PATH}/openspace-data", TESTDIR = "${BASE_PATH}/src/tests", SCENEPATH = "${OPENSPACE_DATA}/scene", + -- SCENEPATH = "${OPENSPACE_DATA}/ABufferVolumes", CONFIG = "${BASE_PATH}/config" }, SGCTConfig = "${SGCT}/single.xml", --SGCTConfig = "${SGCT}/two_nodes.xml", --SGCTConfig = "${SGCT}/single_sbs_stereo.xml", - Scene = "${SCENEPATH}/default.scene" + Scene = "${SCENEPATH}/default.scene", + SpiceTimeKernel = "${OPENSPACE_DATA}/spice/naif0010.tls", + StartupScripts = { + "${SCRIPTS}/default_startup.lua" + } } \ No newline at end of file diff --git a/scripts/DefaultConfig.lua b/scripts/DefaultConfig.lua deleted file mode 100644 index 3e0738115a..0000000000 --- a/scripts/DefaultConfig.lua +++ /dev/null @@ -1,16 +0,0 @@ -{ - level1_string = "music1", - level1_integer = 2332, - level1_dictionary = - { - level2_string = "stuff", - level2_integer = 32, - level2_dictionary = { - level3_string = "levels", - level3_integer = 323232 - } - }, - level2_double = 3.4, - level2_boolean = true - -} \ No newline at end of file diff --git a/scripts/ExtraConfigScript.lua b/scripts/ExtraConfigScript.lua deleted file mode 100644 index a2b9ca86c5..0000000000 --- a/scripts/ExtraConfigScript.lua +++ /dev/null @@ -1,15 +0,0 @@ -musicname = "music2" -lyrics = "This is not, the greatest lyrics in the world. This is just a tribute" - -config = -{ - level1_string = musicname, - level1_lyrics = lyrics, - level1_secrets = - { - secret_stuff1 = "Password", - secret_stuff2 = "123456", - }, - level2_double = 4.3 - -} \ No newline at end of file diff --git a/scripts/config.lua b/scripts/config.lua deleted file mode 100644 index 1cd7d986d2..0000000000 --- a/scripts/config.lua +++ /dev/null @@ -1,5 +0,0 @@ -{ - setting1 = 1, - setting2 = 2, - t = {s = 1, t = 2, u = 3} -} \ No newline at end of file diff --git a/scripts/config2.lua b/scripts/config2.lua deleted file mode 100644 index db728fe51c..0000000000 --- a/scripts/config2.lua +++ /dev/null @@ -1,6 +0,0 @@ -{ - setting2 = 4, - setting3 = 1, - t = { s = 2, v = 0}, - tt = { t = { a = "a", b = "b", ff="2" }, u = { a = "a", b = "b" } } -} \ No newline at end of file diff --git a/scripts/defaultSettings.cfg b/scripts/defaultSettings.cfg deleted file mode 100644 index d93b7d07f8..0000000000 --- a/scripts/defaultSettings.cfg +++ /dev/null @@ -1,4 +0,0 @@ -{ - BasePathOffset = "../../.." - -} \ No newline at end of file diff --git a/scripts/default_startup.lua b/scripts/default_startup.lua new file mode 100644 index 0000000000..f3d66d3ddc --- /dev/null +++ b/scripts/default_startup.lua @@ -0,0 +1,5 @@ +--openspace.setPropertyValue('Earth.renderable.colorTexture', '${OPENSPACE_DATA}/modules/mars/textures/mars.png') +openspace.time.setTime("2000-01-01T00:00:00") +openspace.time.setDeltaTime(0.0) + +print(openspace.time.currentTimeUTC()) diff --git a/shaders/ABuffer/abufferAddToBuffer.hglsl b/shaders/ABuffer/abufferAddToBuffer.hglsl new file mode 100644 index 0000000000..92248796c0 --- /dev/null +++ b/shaders/ABuffer/abufferAddToBuffer.hglsl @@ -0,0 +1,102 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED +layout (binding = 0, r32ui) uniform uimage2D anchorPointerTexture; +layout (binding = 1, rgba32ui) uniform uimageBuffer fragmentTexture; +layout (binding = 0, offset = 0) uniform atomic_uint atomicCounterBuffer; +#endif + +#if ABUFFER_IMPLEMENTATION == ABUFFER_FIXED +layout (binding = 0, r32ui) uniform uimage2D anchorPointerTexture; +layout (binding = 1, rgba32ui) uniform uimageBuffer fragmentTexture; + + #define _MAX_LAYERS_ 16 + #define _SCREEN_WIDTH_ 1280 + #define _SCREEN_HEIGHT_ 720 +#endif + +ABufferStruct_t createGeometryFragment(vec4 fragColor, vec4 position, float z = gl_FragCoord.z) { + ABufferStruct_t frag; + _col_(frag, fragColor); + _z_(frag, z); + _type_(frag, 0); + _pos_(frag, position); + return frag; +} + +void addToBuffer(ABufferStruct_t frag) { + +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED + uint index = atomicCounterIncrement(atomicCounterBuffer); + index *= 2; + uint old_head = imageAtomicExchange(anchorPointerTexture, ivec2(gl_FragCoord.xy), index); + _next_(frag,old_head); + + uvec4 p1 = uvec4(frag.z, frag.id, frag.rg, frag.ba); + uvec4 p2 = uvec4(floatBitsToUint(frag.position.x),floatBitsToUint(frag.position.y),floatBitsToUint(frag.position.z),floatBitsToUint(frag.position.w)); + + imageStore(fragmentTexture, int(index), p1); + imageStore(fragmentTexture, int(index+1), p2); +#endif + +#if ABUFFER_IMPLEMENTATION == ABUFFER_FIXED + uint index = imageAtomicAdd(anchorPointerTexture, ivec2(gl_FragCoord.xy), 1); + if(index < _MAX_LAYERS_) { + int offset = (int(gl_FragCoord.y) * _SCREEN_WIDTH_ + int(gl_FragCoord.x))*_MAX_LAYERS_ + int(index)*2; + + uvec4 p1 = uvec4(frag.z, frag.id, frag.rg, frag.ba); + uvec4 p2 = uvec4(floatBitsToUint(frag.position.x),floatBitsToUint(frag.position.y),floatBitsToUint(frag.position.z),floatBitsToUint(frag.position.w)); + + imageStore(fragmentTexture, int(offset ), p1); + imageStore(fragmentTexture, int(offset+1), p2); + } else { + imageAtomicAdd(anchorPointerTexture, ivec2(gl_FragCoord.xy), -1); + } + +#endif + +} + +ABufferStruct_t loadFromBuffer(uint id) { + +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED + uvec4 u1 = imageLoad(fragmentTexture, int(id)); + uvec4 u2 = imageLoad(fragmentTexture, int(id+1)); +#endif + +#if ABUFFER_IMPLEMENTATION == ABUFFER_FIXED + int offset = (int(gl_FragCoord.y) * _SCREEN_WIDTH_ + int(gl_FragCoord.x))*_MAX_LAYERS_ + int(id)*2; + uvec4 u1 = imageLoad(fragmentTexture, int(offset)); + uvec4 u2 = imageLoad(fragmentTexture, int(offset+1)); +#endif + + vec4 position = vec4( uintBitsToFloat(u2.x), + uintBitsToFloat(u2.y), + uintBitsToFloat(u2.z), + uintBitsToFloat(u2.w)); + + return ABufferStruct_t(u1.x, u1.y, u1.z, u1.w, position); + +} \ No newline at end of file diff --git a/shaders/ABuffer/abufferResolveFragment.glsl b/shaders/ABuffer/abufferResolveFragment.glsl new file mode 100644 index 0000000000..c076cad685 --- /dev/null +++ b/shaders/ABuffer/abufferResolveFragment.glsl @@ -0,0 +1,295 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version 430 + +// ================================================================================ +// Settings +// ================================================================================ +#pragma openspace insert SETTINGS + +// Select type of depth calculations +#define PSCDEPTH 1 +#define ZDEPTH 2 +#define ZTYPE ZDEPTH + +// Maximum number of fragments +#define MAX_FRAGMENTS 16 // The size of the local fragment list +// #define VISUALIZE_TRANSFERFUNCTIONS // +#define USE_JITTERING // +// #define USE_COLORNORMALIZATION // + +// If you need to render a volume box but not sample the volume (debug purpose) +// #define SKIP_VOLUME_0 +// #define SKIP_VOLUME_1 +// #define SKIP_VOLUME_2 +// #define SKIP_VOLUME_3 + +// constants +const float stepSize = 0.01; +const float samplingRate = 1.0; +uniform float ALPHA_LIMIT = 0.99; + + +// Math defintions +#define M_E 2.7182818284590452354 +#define M_LOG2E 1.4426950408889634074 /* log_2 e */ +#define M_LOG10E 0.43429448190325182765 /* log_10 e */ +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#define M_PI_4 0.78539816339744830962 /* pi/4 */ +#define M_1_PI 0.31830988618379067154 /* 1/pi */ +#define M_2_PI 0.63661977236758134308 /* 2/pi */ +#define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#define M_SQRT1_3 0.57735026919 /* 1/sqrt(3) */ + +in vec2 texCoord; +out vec4 out_color; + +// ================================================================================ +// Headers, +// volume and transferfunctions uniforms +// ================================================================================ +#pragma openspace insert HEADERS + +// ================================================================================ +// The ABuffer specific includes and definitions +// ================================================================================ +#include "abufferStruct.hglsl" +ABufferStruct_t fragments[MAX_FRAGMENTS]; + +#if MAX_VOLUMES > 0 + vec3 volume_direction[MAX_VOLUMES]; + float volume_length[MAX_VOLUMES]; + vec3 volume_position[MAX_VOLUMES]; + int volumes_in_fragment[MAX_VOLUMES]; + int volume_count = 0; + + #if ZTYPE == ZDEPTH + vec2 volume_zlength[MAX_VOLUMES]; + #elif ZTYPE == PSCDEPTH + float volume_zlength[MAX_VOLUMES]; + #endif +#endif +#include "abufferSort.hglsl" + +// ================================================================================ +// Helper functions functions +// ================================================================================ +vec3 CartesianToSpherical(vec3 _cartesian) { + // Put cartesian in [-1..1] range first + vec3 cartesian = vec3(-1.0,-1.0,-1.0) + _cartesian * 2.0f; + + float r = length(cartesian); + float theta, phi; + + if (r == 0.0) { + theta = phi = 0.0; + } else { + theta = acos(cartesian.z/r) / M_PI; + phi = (M_PI + atan(cartesian.y, cartesian.x)) / (2.0*M_PI ); + } + r *= M_SQRT1_3; + // r = r / sqrt(3.0f); + + // Sampler ignores w component + return vec3(r, theta, phi); +} + +vec4 blend(vec4 src, vec4 dst) { + vec4 o; + o.a = src.a + dst.a * (1.0f - src.a); + o.rgb = (src.rgb*src.a + dst.rgb*dst.a* (1.0f - src.a)); + return o; + //return mix(src, dst, dst.a*(1.0f - src.a)); +} + +void blendStep(inout vec4 dst, in vec4 src, in float stepSize) { + src.a = 1.0 - pow(1.0 - src.a, stepSize ); + // src.a = 1.0 -(1.0 - src.a*stepSize); + dst.rgb = dst.rgb + (1.0 - dst.a) * src.a * src.rgb; + dst.a = dst.a + (1.0 -dst.a) * src.a; +} + +float volumeRaycastingDistance(in int id, in ABufferStruct_t startFrag, in ABufferStruct_t endFrag) { +#if MAX_VOLUMES > 0 +#if ZTYPE == ZDEPTH + const float S1 = volume_zlength[id].x; + const float S2 = volume_zlength[id].y; + const float L = S1 - S2; + // const float z1 = globz(_z_(startFrag)); + // const float z2 = globz(_z_(endFrag)); + const float z1 = _z_(startFrag); + const float z2 = _z_(endFrag); + return ((z1 - S1) / L - (z2 - S1) / L) * volume_length[id]; +#elif ZTYPE == PSCDEPTH + const float L = volume_zlength[id]; + const vec4 p1 = _pos_(startFrag); + const vec4 p2 = _pos_(endFrag); + const float dist = pscLength(p1, p2); + // const float z1 = _z_(startFrag); + // const float z2 = _z_(endFrag); + return (dist / L) * volume_length[id]; +#endif +#else + return 0.f; +#endif +} + +vec4 calculate_final_color(uint frag_count) { + // volumeStepSize[volID] = 0.01; + int currentVolumeBitmask = 0; + vec4 final_color = vec4(0); + + if(frag_count == 1 && _type_(fragments[0]) == 0) { + final_color = blend(final_color, _col_(fragments[0])); + return final_color; + } + + int frag_count_1 = int(frag_count)-1; + for(int i = 0; i < frag_count_1 && final_color.a < ALPHA_LIMIT; i++) { + + ABufferStruct_t startFrag = fragments[i]; + ABufferStruct_t endFrag = fragments[i+1]; + int type = int(_type_(startFrag)); + + if(type == 0) { + //blendStep(final_color, _col_(startFrag), stepSize); + final_color = blend(final_color, _col_(startFrag)); + } else { + currentVolumeBitmask = currentVolumeBitmask ^ (1 << (type-1)); + } + + +#if MAX_VOLUMES > 0 + if(currentVolumeBitmask > 0) { + + + int volID; + float myMaxSteps = 0.0000001; + if(volume_count > 1) { + for(int v = 0; v < volume_count; ++v) { + int vol = volumes_in_fragment[v]; + float l = volumeRaycastingDistance(vol, startFrag, endFrag); + myMaxSteps = max(myMaxSteps, l/volumeStepSizeOriginal[vol]); + } + + for(int v = 0; v < volume_count; ++v) { + int vol = volumes_in_fragment[v]; + float l = volumeRaycastingDistance(vol, startFrag, endFrag); + float aaa = l/myMaxSteps; + volumeStepSize[vol] = aaa; + volID = vol; + } + } else { + volID = type -1; + } + + float l = volumeRaycastingDistance(volID, startFrag, endFrag); + int max_iterations = int(l / volumeStepSize[volID]); + + // TransferFunction + vec4 color = vec4(0); + for(int k = 0; k < max_iterations && final_color.a < ALPHA_LIMIT && k < LOOP_LIMIT; ++k) { + +#pragma openspace insert SAMPLERCALLS + + + } + + } +#endif + + + + + //blendGeometry(final_color, startFrag); + //if(i == maxFrags -1 && _type_(endFrag) == 0) + // blendGeometry(final_color, endFrag); + + // final_color = blend(final_color, frag_color); + if(i == frag_count_1 -1 && _type_(endFrag) == 0) + // if(i == frag_count_1 -1) + final_color = blend(final_color, _col_(endFrag)); + + } + // final_color = vec4(0); + // int id =3; + // if(id < frag_count)final_color = blend(final_color, _col_(fragments[id])); + + // if(frag_count > 0) + // final_color = _col_(fragments[0]); + +// ================================================================================ +// Transferfunction visualizer +// ================================================================================ +#ifdef VISUALIZE_TRANSFERFUNCTIONS +#pragma openspace insert TRANSFERFUNC +#endif + + // if(frag_count == 1) { + // final_color = vec4(1.0,0.0,0.0,1.0); + // } else if(frag_count == 2) { + // final_color = vec4(0.0,1.0,0.0,1.0); + // // final_color = vec4(volume_direction[0],1.0); + // } else if(frag_count == 3) { + // final_color = vec4(0.0,0.0,1.0,1.0); + // // final_color = vec4(volume_direction[0],1.0); + // } else if(frag_count == 4) { + // final_color = vec4(1.0,1.0,0.0,1.0); + // // final_color = vec4(volume_direction[0],1.0); + // } else { + // final_color = vec4(1.0,1.0,1.0,1.0); + // } + +#ifdef USE_COLORNORMALIZATION + final_color.rgb = final_color.rgb * final_color.a; + final_color.a = 1.0; +#endif + + return final_color; + +} + +// ================================================================================ +// Main function +// ================================================================================ +void main() { + out_color = vec4(texCoord,0.0,1.0); + int frag_count = build_local_fragments_list(); + sort_fragments_list(frag_count); + out_color = calculate_final_color(frag_count); +} + +// ================================================================================ +// The samplers implementations +// ================================================================================ +#pragma openspace insert SAMPLERS + + + diff --git a/shaders/ABuffer/abufferResolveVertex.glsl b/shaders/ABuffer/abufferResolveVertex.glsl new file mode 100644 index 0000000000..301a151753 --- /dev/null +++ b/shaders/ABuffer/abufferResolveVertex.glsl @@ -0,0 +1,33 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version 430 + +in vec4 position; +out vec2 texCoord; + +void main() { + gl_Position = position; + texCoord = 0.5 + position.xy / 2.0; +} diff --git a/shaders/ABuffer/abufferSort.hglsl b/shaders/ABuffer/abufferSort.hglsl new file mode 100644 index 0000000000..71acc355b7 --- /dev/null +++ b/shaders/ABuffer/abufferSort.hglsl @@ -0,0 +1,141 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "abufferAddToBuffer.hglsl" + +uniform float volumeStepFactor = 1.0f; + +int build_local_fragments_list() { + +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED + uint current; + int frag_count = 0; + + current = imageLoad(anchorPointerTexture, ivec2(gl_FragCoord.xy)).x; + + while(current != 0 && frag_count < MAX_FRAGMENTS) { + ABufferStruct_t item = loadFromBuffer(current); + current = _next_(item); + + fragments[frag_count] = item; + + frag_count++; + } + + return frag_count; +#endif + +#if ABUFFER_IMPLEMENTATION == ABUFFER_FIXED + uint frag_count = imageLoad(anchorPointerTexture, ivec2(gl_FragCoord.xy)).x; + + int i; + for(i = 0; i < frag_count && i < MAX_FRAGMENTS; ++i) { + fragments[i] = loadFromBuffer(i); + } + + return int(frag_count); +#endif + +} + +float pscLength(vec4 v1, vec4 v2) { + const float k = 10.0; + float ds = v2.w - v1.w; + vec4 vector; + if(ds >= 0) { + float p = pow(k,-ds); + vector = vec4(v1.x*p - v2.x, v1.y*p - v2.y, v1.z*p - v2.z, v2.w); + } else { + float p = pow(k,ds); + vector = vec4(v1.x - v2.x*p, v1.y - v2.y*p, v1.z - v2.z*p, v1.w); + } + return length(vector.xyz)*pow(k,vector.w); +} + +float permute(float i) { + return mod((62.0*i*i + i), 961.0); // permutation polynomial; 62=2*31; 961=31*31 +} + +void sort_fragments_list(uint frag_count) { + uint i,j; + ABufferStruct_t tmp; + + // INSERTION SORT + for(i = 1; i < frag_count; ++i) { + tmp = fragments[i]; + for(j = i; j > 0 && _z_(tmp) < _z_(fragments[j-1]); --j) { + fragments[j] = fragments[j-1]; + } + fragments[j] = tmp; + } + +#if MAX_VOLUMES > 0 + int ii, jj; + for(ii = 0; ii < MAX_VOLUMES; ++ii) { + bool start = true; + vec3 startColor; + vec4 startPosition; + for(jj = 0; jj < frag_count; ++jj) { + int type = int(_type_(fragments[jj])) - 1; + if(type== ii) { + if(start) { + startColor = _col_(fragments[jj]).rgb; + startPosition = _pos_(fragments[jj]); +#if ZTYPE == ZDEPTH + volume_zlength[ii].x = _z_(fragments[jj]); +#endif + start = false; + } else { + volumes_in_fragment[volume_count++] = ii; + vec3 dir = _col_(fragments[jj]).rgb - startColor; + volume_position[ii] = startColor; + volume_length[ii] = length(dir); + volume_direction[ii] = normalize(dir); + volumeStepSize[ii] = 1.0/(volumeStepFactor * length(volume_direction[ii]*volume_dim[ii])); + volumeStepSizeOriginal[ii] = volumeStepSize[ii]; +#if ZTYPE == ZDEPTH + volume_zlength[ii].y = _z_(fragments[jj]); +#elif ZTYPE == PSCDEPTH + volume_zlength[ii] = pscLength(_pos_(fragments[jj]), startPosition); +#endif +#ifdef USE_JITTERING + if(volumeStepSize[ii] < volume_length[ii]) { + // jittering + float x = gl_FragCoord.x; + float y = gl_FragCoord.y; + float jitterValue = float(permute(x + permute(y))) / 961.0; + vec3 frontPosNew = startColor + (jitterValue*volumeStepSize[ii])*volume_direction[ii]; + volume_position[ii] = frontPosNew; + } +#endif + + break; + } + } + } + } +#endif + //volume_direction[0] = vec3(1.0,0.0,0.0); + //volume_direction[0] = _col_(fragments[0]).rgb; +} diff --git a/shaders/ABuffer/abufferStruct.hglsl b/shaders/ABuffer/abufferStruct.hglsl new file mode 100644 index 0000000000..5c510c4bd0 --- /dev/null +++ b/shaders/ABuffer/abufferStruct.hglsl @@ -0,0 +1,162 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef ABUFFERSTRUCT_H_HGLSL +#define ABUFFERSTRUCT_H_HGLSL + +// The different kinds of implementation, set from OpenSpace +// #define ABUFFER_SINGLE_LINKED 1 +// #define ABUFFER_FIXED 2 +// #define ABUFFER_DYNAMIC 3 +// #define ABUFFER_IMPLEMENTATION ABUFFER_SINGLE_LINKED + + +//======================================================================================== +// ABufferStruct_t declaration +//======================================================================================== +// struct ABufferStruct_t { +// uint z; // the depth value +// uint id; // bits 0-28 next, bits 29-32 type +// vec4 color; // packed rgba +// //vec4 position; // packed position +// // uint padding1; +// // uint padding2; +// }; +struct ABufferStruct_t { + uint z; // the depth value + uint id; // bits 0-28 next, bits 29-32 type + uint rg; // packed red green color + uint ba; // packed blue alpha color + vec4 position; // position +}; + + +//======================================================================================== +// Bitwise operations +//======================================================================================== +const uint mask_1 = 1; +const uint mask_8 = 255; +const uint mask_16 = 65535; +const uint mask_24 = 16777215; +const uint mask_29 = 536870911; +const uint mask_30 = 1073741823; +const uint mask_31 = 2147483647; +const uint mask_32 = 4294967295; +const uint mask_id = mask_16; +const uint shift_id = 0; +const uint mask_type = mask_24 - mask_16; +const uint shift_type = 16; +/* +const uint mask_zid_z = mask_24; +const uint shift_zid_z = 0; +const uint mask_zid_id = mask_29 - mask_24; +const uint shift_zid_id = 24; +const uint mask_zid_type = mask_31 - mask_29; +const uint shift_zid_type = 29; +const uint mask_zid_xxx = mask_32 - mask_31; +const uint shift_zid_xxx = 31; +*/ + +const uint mask_id_next = mask_29; +const uint shift_id_next = 0; +const uint mask_id_type = mask_32 - mask_29; +const uint shift_id_type = 29; + +void bitinsert_u(inout uint pack, uint val, uint mask, uint shift) { + pack &= ~mask; + pack |= (val << shift) & mask; +} +uint bitextract_u(in uint pack, uint mask, uint shift) { + return (pack >> shift) & (mask >> shift); +} +void bitinsert_i(inout int pack, int val, uint mask, uint shift) { + pack &= int( ~mask ); + pack |= int( (uint(val) << shift) & mask ); +} +int bitextract_i(in int pack, uint mask, uint shift) { + return int( (uint(pack) >> shift) & (mask >> shift) ); +} + +//======================================================================================== +// Access functions +//======================================================================================== +float _z_(ABufferStruct_t frag) { + return uintBitsToFloat(frag.z); +} +void _z_(inout ABufferStruct_t frag, float z) { + frag.z = floatBitsToUint(z); +} + +vec4 _pos_(ABufferStruct_t frag) { + // return vec4(0.0,0.0,0.0,0.0); + return frag.position; + //return unpackUnorm4x8(frag.position); +} +void _pos_(inout ABufferStruct_t frag, vec4 position) { + frag.position = position; + // frag.position = packUnorm4x8(position); +} + +vec4 _col_(ABufferStruct_t frag) { + return vec4(unpackUnorm2x16(frag.rg),unpackUnorm2x16(frag.ba)); + //return unpackUnorm4x8(frag.color); +} +void _col_(inout ABufferStruct_t frag, vec4 color) { + frag.rg = packUnorm2x16(color.rg); + frag.ba = packUnorm2x16(color.ba); + //frag.color = packUnorm4x8(color); +} + +uint _type_(ABufferStruct_t frag) { +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED + return bitextract_u(frag.id, mask_id_type, shift_id_type); +#else + return frag.id; +#endif +} +void _type_(inout ABufferStruct_t frag, uint type) { +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED + bitinsert_u(frag.id, type, mask_id_type, shift_id_type); +#else + frag.id = type; +#endif +} + +//======================================================================================== +// Implementation specific functions +//======================================================================================== + +// _next_ is only needed for the single linked implementation +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED +uint _next_(ABufferStruct_t frag) { + return bitextract_u(frag.id, mask_id_next, shift_id_next); + //return frag.id; +} +void _next_(inout ABufferStruct_t frag, uint id) { + bitinsert_u(frag.id, id, mask_id_next, shift_id_next); + //frag.id = id; +} +#endif + +#endif \ No newline at end of file diff --git a/shaders/PowerScaling/powerScaling_fs.hglsl b/shaders/PowerScaling/powerScaling_fs.hglsl new file mode 100644 index 0000000000..c227016f1d --- /dev/null +++ b/shaders/PowerScaling/powerScaling_fs.hglsl @@ -0,0 +1,90 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef POWERSCALING_FS_H_HGLSL +#define POWERSCALING_FS_H_HGLSL + +// Observable universe is 10^27m, setting the far value to extremely high, aka 30!! ERMAHGERD! + +const float k = 10.0; +const float s_far = 27.0f; //= gl_DepthRange.far; // 40 +const float s_farcutoff = 12.0f; +const float s_nearcutoff = 7.00f; +const float s_near = 0.00f;// gl_DepthRange.near; // 0.1 + +vec4 psc_normlization(vec4 invec) { + + float xymax = max(invec.x,invec.y); + + if(invec.z > 0.0f || invec.z < 0.0f) { + return invec / abs(invec.z); + } else if (xymax != 0.0f) { + return invec / xymax; + } else { + return invec / -.0; + } +} + +float pscDepth(vec4 position) { + float depth = 0.0f; + if(position.w <= 0.5) { + //depth = abs(position.z * pow(10, position.w)) / pow(k,s_far); + depth = (position.w+log(abs(position.z)))/pow(k, position.w); + } else if(position.w < 3.0) { + depth = position.w+log(abs(position.z))/pow(k, position.w); + } else { + depth = position.w+log(abs(position.z)); + } + + + // DEBUG + float depth_orig = depth; + float x = 0.0f; + float cutoffs = 0.0; + float orig_z = position.z; + + // calculate a normalized depth [0.0 1.0] + if((depth > s_near && depth <= s_nearcutoff) || (depth > s_farcutoff && depth < s_far)) { + + // completely linear interpolation [s_near .. depth .. s_far] + depth = (depth - s_near) / (s_far - s_near); + + } else if(depth > s_nearcutoff && depth < s_farcutoff) { + + // DEBUG + cutoffs = 1.0; + + // interpolate [10^s_nearcutoff .. 10^depth .. 10^s_farcutoff] + // calculate between 0..1 where the depth is + x = (pow(10,depth) - pow(10, s_nearcutoff)) / (pow(10,s_farcutoff) - pow(10, s_nearcutoff)); + + // remap the depth to the 0..1 depth buffer + depth = s_nearcutoff + x * (s_farcutoff - s_nearcutoff); + depth = (depth - s_near) / (s_far - s_near); + + } + return depth; +} + +#endif \ No newline at end of file diff --git a/shaders/PowerScaling/powerScaling_vs.hglsl b/shaders/PowerScaling/powerScaling_vs.hglsl new file mode 100644 index 0000000000..0ec24564b7 --- /dev/null +++ b/shaders/PowerScaling/powerScaling_vs.hglsl @@ -0,0 +1,80 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef POWERSCALING_VS_H_HGLSL +#define POWERSCALING_VS_H_HGLSL + +const float k = 10.0; + +vec4 psc_addition(vec4 v1, vec4 v2) { + float ds = v2.w - v1.w; + if(ds >= 0) { + float p = pow(k,-ds); + return vec4(v1.x*p + v2.x, v1.y*p + v2.y, v1.z*p + v2.z, v2.w); + } else { + float p = pow(k,ds); + return vec4(v1.x + v2.x*p, v1.y + v2.y*p, v1.z + v2.z*p, v1.w); + } +} + +vec4 psc_to_meter(vec4 v1, vec2 v2) { + float factor = v2.x * pow(k,v2.y + v1.w); + return vec4(v1.xyz * factor, 1.0); +} + +vec4 psc_scaling(vec4 v1, vec2 v2) { + float ds = v2.y - v1.w; + if(ds >= 0) { + return vec4(v1.xyz * v2.x * pow(k,v1.w), v2.y); + } else { + return vec4(v1.xyz * v2.x * pow(k,v2.y), v1.w); + } +} + +vec4 pscTransform(vec4 vertexPosition, vec4 cameraPosition, vec2 scaling, mat4 modelTransform) { + vec3 local_vertex_pos = mat3(modelTransform) * vertexPosition.xyz; + //vec4 lvp = ModelTransform * vertexPosition; + + // PSC addition; local vertex position and the object power scaled world position + vec4 position = psc_addition(vec4(local_vertex_pos,vertexPosition.w),objpos); + //position = psc_addition(lvp,objpos); + + // PSC addition; rotated and viewscaled vertex and the cmaeras negative position + position = psc_addition(position,vec4(-cameraPosition.xyz,cameraPosition.w)); + + // rotate the camera + local_vertex_pos = mat3(camrot) * position.xyz; + position = vec4(local_vertex_pos, position.w); + //position = camrot* position; + + // rescales the scene to fit inside the view frustum + // is set from the main program, but these are decent values + // scaling = vec2(1.0, -8.0); + + // project using the rescaled coordinates, + //vec4 vs_position_rescaled = psc_scaling(position, scaling); + return psc_to_meter(position, scaling); +} + +#endif \ No newline at end of file diff --git a/shaders/cubeFrag.glsl b/shaders/cubeFrag.glsl index 0b6be3de9a..292f1396c8 100644 --- a/shaders/cubeFrag.glsl +++ b/shaders/cubeFrag.glsl @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 330 in vec4 color; diff --git a/shaders/cubeVert.glsl b/shaders/cubeVert.glsl index 68a1d89d43..38393b3e3f 100644 --- a/shaders/cubeVert.glsl +++ b/shaders/cubeVert.glsl @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 330 uniform mat4 projectionMatrix; diff --git a/shaders/exitpoints.frag b/shaders/exitpoints.frag index 1ea86ecb38..71dac97245 100644 --- a/shaders/exitpoints.frag +++ b/shaders/exitpoints.frag @@ -1,8 +1,52 @@ -#version 400 core +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version 430 core + +uniform int volumeType; in vec3 vPosition; -out vec4 fragColor; +in vec3 worldPosition; +in float s; + +#include "ABuffer/abufferStruct.hglsl" +#include "ABuffer/abufferAddToBuffer.hglsl" +#include "PowerScaling/powerScaling_fs.hglsl" void main() { - fragColor = vec4(vPosition+0.5, 1.0); + vec4 fragColor = vec4(vPosition+0.5, 1.0); + vec4 position = vec4(worldPosition,s); + float depth = pscDepth(position); + + gl_FragDepth = depth; + + ABufferStruct_t frag; + _col_(frag, fragColor); + _z_(frag, depth); + _type_(frag, volumeType); + _pos_(frag, position); + addToBuffer(frag); + + discard; } \ No newline at end of file diff --git a/shaders/exitpoints.vert b/shaders/exitpoints.vert index 0668ef5618..a3295d3a6f 100644 --- a/shaders/exitpoints.vert +++ b/shaders/exitpoints.vert @@ -1,11 +1,62 @@ -#version 400 core +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version 430 core + +layout(location = 0) in vec4 vertPosition; -layout(location = 2) in vec3 vertPosition; uniform mat4 modelViewProjection; +uniform mat4 modelTransform; +uniform vec4 campos; +uniform mat4 camrot; +uniform vec2 scaling; +uniform vec4 objpos; out vec3 vPosition; +out vec3 worldPosition; +out float s; + +#include "PowerScaling/powerScaling_vs.hglsl" void main() { - gl_Position = modelViewProjection * vec4(vertPosition, 1.0); - vPosition = vertPosition; + + //vs_st = in_st; + //vs_stp = in_position.xyz; + + vPosition = vertPosition.xyz; + + // this is wrong for the normal. The normal transform is the transposed inverse of the model transform + //vs_normal = normalize(modelTransform * vec4(in_normal,0)); + + vec4 position = pscTransform(vertPosition, campos, scaling, modelTransform); + worldPosition = position.xyz; + s = position.w; + + // project the position to view space + gl_Position = modelViewProjection * position; + + // vPosition = vertPosition.xyz; + // worldPosition = (modelTransform *vec4(vPosition, 1.0)).xyz; + // gl_Position = modelViewProjection *vec4(worldPosition, 1.0); } \ No newline at end of file diff --git a/shaders/pscstandard_fs.glsl b/shaders/pscstandard_fs.glsl index 5cc012fc40..26a3d1987d 100644 --- a/shaders/pscstandard_fs.glsl +++ b/shaders/pscstandard_fs.glsl @@ -1,115 +1,49 @@ -/** -Copyright (C) 2012-2014 Jonas Strandstedt +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +#version 430 -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ -#version 400 core - -uniform mat4 ViewProjection; -uniform mat4 ModelTransform; -uniform vec4 campos; -uniform vec4 objpos; uniform float time; uniform sampler2D texture1; -uniform sampler2D texture2; -uniform sampler2D texture3; -uniform float TessLevel; -uniform bool Wireframe; -uniform bool Lightsource; -uniform bool UseTexture; in vec2 vs_st; -//in vec3 vs_stp; in vec4 vs_normal; -in vec4 vs_position; +in vec3 vs_position; +in float s; -out vec4 diffuse; - -const float k = 10.0; - -vec4 psc_normlization(vec4 invec) { - - float xymax = max(invec.x,invec.y); - - if(invec.z > 0.0f || invec.z < 0.0f) { - return invec / abs(invec.z); - } else if (xymax != 0.0f) { - return invec / xymax; - } else { - return invec / -.0; - } -} +#include "ABuffer/abufferStruct.hglsl" +#include "ABuffer/abufferAddToBuffer.hglsl" +#include "PowerScaling/powerScaling_fs.hglsl" void main() { + vec4 position = vec4(vs_position,s); + float depth = pscDepth(position); + vec4 diffuse = texture(texture1, vs_st); - // Observable universe is 10^27m, setting the far value to extremely high, aka 30!! ERMAHGERD! - float s_far = 40.0; //= gl_DepthRange.far; // 40 - float s_farcutoff = 12.0; - float s_nearcutoff = 7.0; - float s_near = 0.0f;// gl_DepthRange.near; // 0.1 - float depth; + ABufferStruct_t frag = createGeometryFragment(diffuse, position, depth); + addToBuffer(frag); - // the value can be normalized to 1 - - vec4 p = vs_position; - if(vs_position.w <= 0.5) { - //depth = abs(vs_position.z * pow(10, vs_position.w)) / pow(k,s_far); - depth = (vs_position.w+log(abs(vs_position.z)))/pow(k, vs_position.w); - } else if(vs_position.w < 3.0) { - depth = vs_position.w+log(abs(vs_position.z))/pow(k, vs_position.w); - } else { - depth = vs_position.w+log(abs(vs_position.z)); - } - - - // DEBUG - float depth_orig = depth; - float x = 0.0f; - float cutoffs = 0.0; - float orig_z = vs_position.z; - - // calculate a normalized depth [0.0 1.0] - if((depth > s_near && depth <= s_nearcutoff) || (depth > s_farcutoff && depth < s_far)) { - - // completely linear interpolation [s_near .. depth .. s_far] - depth = (depth - s_near) / (s_far - s_near); - - } else if(depth > s_nearcutoff && depth < s_farcutoff) { - - // DEBUG - cutoffs = 1.0; - - // interpolate [10^s_nearcutoff .. 10^depth .. 10^s_farcutoff] - // calculate between 0..1 where the depth is - x = (pow(10,depth) - pow(10, s_nearcutoff)) / (pow(10,s_farcutoff) - pow(10, s_nearcutoff)); - - // remap the depth to the 0..1 depth buffer - depth = s_nearcutoff + x * (s_farcutoff - s_nearcutoff); - depth = (depth - s_near) / (s_far - s_near); - - } else { - // where am I? - // do I need to be discarded? - // discard; - } - - - // set the depth - gl_FragDepth = depth; - //gl_FragDepth = 0.5; - - // color - diffuse = texture(texture1, vs_st); - //diffuse = vec4(vs_position.z,0.0, 0.0, 1.0); - // diffuse = vec4(vs_position.xyz * pow(10, vs_position.w), 1.0); - //diffuse = vec4(vs_st, 0.0, 1.0); - //diffuse = vec4(1.0,1.0, 0.0, 1.0); - //diffuse = vec4(depth*5,0.0, 0.0, 1.0); - //diffuse = vec4(vs_position.w,0.0, 0.0, 1.0); - //diffuse = vec4(1.0,0.0,0.0,1.0); + discard; } \ No newline at end of file diff --git a/shaders/pscstandard_vs.glsl b/shaders/pscstandard_vs.glsl index 7410c300f6..e9e1745dc9 100644 --- a/shaders/pscstandard_vs.glsl +++ b/shaders/pscstandard_vs.glsl @@ -1,25 +1,28 @@ -/** -Copyright (C) 2012-2014 Jonas Strandstedt +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ -#version 400 core +#version 430 uniform mat4 ViewProjection; uniform mat4 ModelTransform; @@ -28,13 +31,6 @@ uniform mat4 camrot; uniform vec2 scaling; uniform vec4 objpos; uniform float time; -uniform sampler2D texture1; -uniform sampler2D texture2; -uniform sampler2D texture3; -uniform float TessLevel; -uniform bool Wireframe; -uniform bool Lightsource; -uniform bool UseTexture; layout(location = 0) in vec4 in_position; //in vec3 in_position; @@ -44,72 +40,24 @@ layout(location = 2) in vec3 in_normal; out vec2 vs_st; out vec3 vs_stp; out vec4 vs_normal; -out vec4 vs_position; +out vec3 vs_position; +out float s; -const float k = 10.0; -const float dgr_to_rad = 0.0174532925; - -vec4 psc_addition(vec4 v1, vec4 v2) { - float ds = v2.w - v1.w; - if(ds >= 0) { - float p = pow(k,-ds); - return vec4(v1.x*p + v2.x, v1.y*p + v2.y, v1.z*p + v2.z, v2.w); - } else { - float p = pow(k,ds); - return vec4(v1.x + v2.x*p, v1.y + v2.y*p, v1.z + v2.z*p, v1.w); - } -} - -vec4 psc_to_meter(vec4 v1, vec2 v2) { - float factor = v2.x * pow(k,v2.y + v1.w); - return vec4(v1.xyz * factor, 1.0); -} - -vec4 psc_scaling(vec4 v1, vec2 v2) { - float ds = v2.y - v1.w; - if(ds >= 0) { - return vec4(v1.xyz * v2.x * pow(k,v1.w), v2.y); - } else { - return vec4(v1.xyz * v2.x * pow(k,v2.y), v1.w); - } -} +#include "PowerScaling/powerScaling_vs.hglsl" void main() { // set variables vs_st = in_st; //vs_stp = in_position.xyz; + + // this is wrong for the normal. The normal transform is the transposed inverse of the model transform vs_normal = normalize(ModelTransform * vec4(in_normal,0)); - // fetch model and view translation - //vec4 vertex_translate = ModelTransform[3]; - - // rotate and scale vertex with model transform and add the translation - vec3 local_vertex_pos = mat3(ModelTransform) * in_position.xyz; - //vec4 lvp = ModelTransform * in_position; - - // PSC addition; local vertex position and the object power scaled world position - vs_position = psc_addition(vec4(local_vertex_pos,in_position.w),objpos); - //vs_position = psc_addition(lvp,objpos); - - // PSC addition; rotated and viewscaled vertex and the cmaeras negative position - vs_position = psc_addition(vs_position,vec4(-campos.xyz,campos.w)); - - // rotate the camera - local_vertex_pos = mat3(camrot) * vs_position.xyz; - vs_position = vec4(local_vertex_pos, vs_position.w); - //vs_position = camrot* vs_position; - - // rescales the scene to fit inside the view frustum - // is set from the main program, but these are decent values - // scaling = vec2(1.0, -8.0); - - // project using the rescaled coordinates, - //vec4 vs_position_rescaled = psc_scaling(vs_position, scaling); - vec4 vs_position_rescaled = psc_to_meter(vs_position, scaling); - //vs_position = vs_position_rescaled; - + vec4 position = pscTransform(in_position, campos, scaling, ModelTransform); + vs_position = position.xyz; + s = position.w; // project the position to view space - gl_Position = ViewProjection * vs_position_rescaled; + gl_Position = ViewProjection * position; } \ No newline at end of file diff --git a/shaders/quadFrag.glsl b/shaders/quadFrag.glsl index 0b4adc27c0..a52ce0a5f5 100644 --- a/shaders/quadFrag.glsl +++ b/shaders/quadFrag.glsl @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 330 uniform sampler2D quadTex; diff --git a/shaders/quadVert.glsl b/shaders/quadVert.glsl index 2140173049..3221517490 100644 --- a/shaders/quadVert.glsl +++ b/shaders/quadVert.glsl @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 330 layout(location = 0) in vec2 texCoordinate; diff --git a/shaders/quadVertFlare.glsl b/shaders/quadVertFlare.glsl index a3c9b18411..12b7b9fe41 100644 --- a/shaders/quadVertFlare.glsl +++ b/shaders/quadVertFlare.glsl @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 330 in vec4 position; diff --git a/shaders/singlepassraycaster.frag b/shaders/singlepassraycaster.frag index 222c459ae3..e910176269 100644 --- a/shaders/singlepassraycaster.frag +++ b/shaders/singlepassraycaster.frag @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 400 core // Based on http://prideout.net/blog/?p=64 diff --git a/shaders/singlepassraycaster.gs b/shaders/singlepassraycaster.gs index a393169a32..fea6d6b415 100644 --- a/shaders/singlepassraycaster.gs +++ b/shaders/singlepassraycaster.gs @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 400 core // Based on http://prideout.net/blog/?p=64 diff --git a/shaders/singlepassraycaster.vert b/shaders/singlepassraycaster.vert index c33d4689b9..df013c63ae 100644 --- a/shaders/singlepassraycaster.vert +++ b/shaders/singlepassraycaster.vert @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 400 core // Based on http://prideout.net/blog/?p=64 diff --git a/shaders/twopassraycaster.frag b/shaders/twopassraycaster.frag index 1e9daf5cdb..1641c013dd 100644 --- a/shaders/twopassraycaster.frag +++ b/shaders/twopassraycaster.frag @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 400 core uniform sampler2D texBack, texFront; diff --git a/shaders/twopassraycaster.vert b/shaders/twopassraycaster.vert index 164a5e8643..f8453e0f57 100644 --- a/shaders/twopassraycaster.vert +++ b/shaders/twopassraycaster.vert @@ -1,3 +1,27 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + #version 400 core layout(location = 0) in vec2 texCoordinate; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c2d78d2b9e..6b193bdc0f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,6 +34,12 @@ file(GLOB CONFIGURATION_HEADER ${HEADER_ROOT_DIR}/openspace/configuration/*.h) set(OPENSPACE_HEADER ${OPENSPACE_HEADER} ${CONFIGURATION_HEADER}) source_group(Configuration FILES ${CONFIGURATION_SOURCE} ${CONFIGURATION_HEADER}) +file(GLOB ABUFFER_SOURCE ${SOURCE_ROOT_DIR}/abuffer/*.cpp) +set(OPENSPACE_SOURCE ${OPENSPACE_SOURCE} ${ABUFFER_SOURCE}) +file(GLOB ABUFFER_HEADER ${HEADER_ROOT_DIR}/openspace/abuffer/*.h) +set(OPENSPACE_HEADER ${OPENSPACE_HEADER} ${ABUFFER_HEADER}) +source_group(ABuffer FILES ${ABUFFER_SOURCE} ${ABUFFER_HEADER}) + file(GLOB ENGINE_SOURCE ${SOURCE_ROOT_DIR}/engine/*.cpp) set(OPENSPACE_SOURCE ${OPENSPACE_SOURCE} ${ENGINE_SOURCE}) file(GLOB ENGINE_HEADER ${HEADER_ROOT_DIR}/openspace/engine/*.h) @@ -90,6 +96,12 @@ file(GLOB SCENEGRAPH_HEADER ${HEADER_ROOT_DIR}/openspace/scenegraph/*.h ${HEADER set(OPENSPACE_HEADER ${OPENSPACE_HEADER} ${SCENEGRAPH_HEADER}) source_group(SceneGraph FILES ${SCENEGRAPH_SOURCE} ${SCENEGRAPH_HEADER}) +file(GLOB SCRIPTING_SOURCE ${SOURCE_ROOT_DIR}/scripting/*.cpp) +set(OPENSPACE_SOURCE ${OPENSPACE_SOURCE} ${SCRIPTING_SOURCE}) +file(GLOB SCRIPTING_HEADER ${HEADER_ROOT_DIR}/openspace/scripting/*.h) +set(OPENSPACE_HEADER ${OPENSPACE_HEADER} ${SCRIPTING_HEADER}) +source_group(Scripting FILES ${SCRIPTING_SOURCE} ${SCRIPTING_HEADER}) + file(GLOB UTIL_SOURCE ${SOURCE_ROOT_DIR}/util/*.cpp) set(OPENSPACE_SOURCE ${OPENSPACE_SOURCE} ${UTIL_SOURCE}) file(GLOB UTIL_HEADER ${HEADER_ROOT_DIR}/openspace/util/*.h) @@ -136,5 +148,23 @@ include_directories("${HEADER_ROOT_DIR}") add_executable(OpenSpace ${SOURCE_ROOT_DIR}/main.cpp ${OPENSPACE_HEADER} ${OPENSPACE_SOURCE}) target_link_libraries(OpenSpace ${DEPENDENT_LIBS}) +if (WIN32) + if (CMAKE_CL_64) + set(OPENSPACE_DLL_LIBS ${OPENSPACE_DLL_LIBS} ${GHOUL_ROOT_DIR}/ext/il/lib/win64/DevIL.dll) + set(OPENSPACE_DLL_LIBS ${OPENSPACE_DLL_LIBS} ${GHOUL_ROOT_DIR}/ext/il/lib/win64/ILU.dll) + set(OPENSPACE_DLL_LIBS ${OPENSPACE_DLL_LIBS} ${GHOUL_ROOT_DIR}/ext/il/lib/win64/ILUT.dll) + else (CMAKE_CL_64) + set(OPENSPACE_DLL_LIBS ${OPENSPACE_DLL_LIBS} ${GHOUL_ROOT_DIR}/ext/il/lib/win32/DevIL.dll) + set(OPENSPACE_DLL_LIBS ${OPENSPACE_DLL_LIBS} ${GHOUL_ROOT_DIR}/ext/il/lib/win32/ILU.dll) + set(OPENSPACE_DLL_LIBS ${OPENSPACE_DLL_LIBS} ${GHOUL_ROOT_DIR}/ext/il/lib/win32/ILUT.dll) + endif (CMAKE_CL_64) + foreach( file_i ${OPENSPACE_DLL_LIBS}) + add_custom_command(TARGET OpenSpace POST_BUILD # Adds a post-build event to MyTest + COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." + "${file_i}" # <--this is in-file + $) + endforeach( file_i ) +endif(WIN32) + add_subdirectory(tests) diff --git a/src/abuffer/abuffer.cpp b/src/abuffer/abuffer.cpp new file mode 100644 index 0000000000..920a87b24d --- /dev/null +++ b/src/abuffer/abuffer.cpp @@ -0,0 +1,379 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace { + std::string _loggerCat = "ABuffer"; + +std::string padGeneratedString(const std::string& content) { + std::string _content_ = "// GENERATED CONTENT\n" + content + "\n// END GENERATED CONTENT"; + return _content_; +} + +} + +namespace openspace { + +ABuffer::ABuffer(): _validShader(true) { + int x1, xSize, y1, ySize; + sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); + _width = xSize; + _height = ySize; + _totalPixels = _width * _height; + const std::string fragmentShaderSourcePath = absPath("${SHADERS}/ABuffer/abufferResolveFragment.glsl"); + _fragmentShaderFile = new ghoul::filesystem::File(fragmentShaderSourcePath, true); + _fragmentShaderPath = fragmentShaderSourcePath.substr(0, fragmentShaderSourcePath.length()-4) + "gglsl"; +} + +ABuffer::~ABuffer() { + if(_fragmentShaderFile) + delete _fragmentShaderFile; + + if(_resolveShader) + delete _resolveShader; + + for(auto file: _samplerFiles) { + delete file; + } + for(auto file: _shaderFiles) { + delete file; + } + +} + +bool ABuffer::initializeABuffer() { + // ============================ + // SHADERS + // ============================ + auto shaderCallback = [this](const ghoul::filesystem::File& file) { + _validShader = false; + }; + _fragmentShaderFile->setCallback(shaderCallback); + + // Development functionality to update shader for changes in several files + auto addFunc = [this, shaderCallback](const std::string& path) { + ghoul::filesystem::File* f = new ghoul::filesystem::File(path, false); + f->setCallback(shaderCallback); + _shaderFiles.push_back(f); + }; + addFunc("${SHADERS}/ABuffer/abufferSort.hglsl"); + addFunc("${SHADERS}/ABuffer/abufferAddToBuffer.hglsl"); + addFunc("${SHADERS}/ABuffer/abufferStruct.hglsl"); + addFunc("${SHADERS}/PowerScaling/powerScaling_fs.hglsl"); + addFunc("${SHADERS}/PowerScaling/powerScaling_vs.hglsl"); + + _resolveShader = nullptr; + generateShaderSource(); + updateShader(); + + // ============================ + // GEOMETRY (quad) + // ============================ + const GLfloat size = 1.0f; + const GLfloat vertex_data[] = { // square of two triangles (sigh) + // x y z w s t + -size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f, + -size, size, 0.0f, 1.0f, + -size, -size, 0.0f, 1.0f, + size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f, + }; + GLuint vertexPositionBuffer; + glGenVertexArrays(1, &_screenQuad); // generate array + glBindVertexArray(_screenQuad); // bind array + glGenBuffers(1, &vertexPositionBuffer); // generate buffer + glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, reinterpret_cast(0)); + glEnableVertexAttribArray(0); + + return true; +} + +void ABuffer::resolve() { + if( ! _validShader) { + _validShader = true; + generateShaderSource(); + updateShader(); + + } + + if(_resolveShader) { + _resolveShader->activate(); + int startAt = 0; + for(int i = 0; i < _volumes.size(); ++i) { + glActiveTexture(GL_TEXTURE0 + i); + _volumes.at(i).second->bind(); + startAt = i + 1; + } + for(int i = 0; i < _transferFunctions.size(); ++i) { + glActiveTexture(GL_TEXTURE0 + startAt + i); + _transferFunctions.at(i).second->bind(); + } + + // Decrease stepsize in volumes if right click is pressed + // TODO: Let the interactionhandler handle this + int val = sgct::Engine::getMouseButton(0, SGCT_MOUSE_BUTTON_RIGHT); + float volumeStepFactor = (val) ? 0.2: 1.0; + if(volumeStepFactor != _volumeStepFactor) { + _volumeStepFactor = volumeStepFactor; + _resolveShader->setUniform("volumeStepFactor", _volumeStepFactor); + } + + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + + _resolveShader->deactivate(); + } +} + +void ABuffer::addVolume(const std::string& tag,ghoul::opengl::Texture* volume) { + _volumes.push_back(std::make_pair(tag, volume)); +} + +void ABuffer::addTransferFunction(const std::string& tag,ghoul::opengl::Texture* transferFunction) { + _transferFunctions.push_back(std::make_pair(tag, transferFunction)); +} + +int ABuffer::addSamplerfile(const std::string& filename) { + if( ! FileSys.fileExists(filename)) + return -1; + + auto fileCallback = [this](const ghoul::filesystem::File& file) { + _validShader = false; + }; + ghoul::filesystem::File* file = new ghoul::filesystem::File(filename); + file->setCallback(fileCallback); + _samplerFiles.push_back(file); + _samplers.push_back(""); + + // ID is one more than "actual" position since ID=0 is considered geometry + //return 1 << (_samplers.size()-1); + return _samplers.size(); +} + +bool ABuffer::updateShader() { + + using ghoul::opengl::ShaderObject; + using ghoul::opengl::ProgramObject; + ShaderCreator sc = OsEng.shaderBuilder(); + ghoul::opengl::ProgramObject* resolveShader = sc.buildShader("ABuffer resolve", absPath("${SHADERS}/ABuffer/abufferResolveVertex.glsl"), _fragmentShaderPath); + if( ! resolveShader) { + LERROR("Resolve shader not updated"); + return false; + } + + int startAt = 0; + for(int i = 0; i < _volumes.size(); ++i) { + resolveShader->setUniform(_volumes.at(i).first, i); + startAt = i + 1; + } + for(int i = 0; i < _transferFunctions.size(); ++i) { + resolveShader->setUniform(_transferFunctions.at(i).first, startAt + i); + } + + if(_resolveShader) + delete _resolveShader; + + _resolveShader = resolveShader; + LDEBUG("Successfully updated shader!"); + return true; +} + +void ABuffer::generateShaderSource() { + + for(int i = 0; i < _samplerFiles.size(); ++i) { + std::string line, source = ""; + std::ifstream samplerFile(_samplerFiles.at(i)->path()); + if(samplerFile.is_open()) { + while(std::getline(samplerFile, line)) { + source += line + "\n"; + } + } + samplerFile.close(); + _samplers.at(i) = source; + } + + std::string line, source = ""; + std::ifstream fragmentShaderFile(_fragmentShaderFile->path()); + if(fragmentShaderFile.is_open()) { + while(std::getline(fragmentShaderFile, line)) { + if(line == "#pragma openspace insert HEADERS") { + line = padGeneratedString(openspaceHeaders()); + } else if(line == "#pragma openspace insert SAMPLERCALLS") { + line = padGeneratedString(openspaceSamplerCalls()); + } else if(line == "#pragma openspace insert SAMPLERS") { + line = padGeneratedString(openspaceSamplers()); + } else if(line == "#pragma openspace insert SETTINGS") { + line = padGeneratedString(settings()); + } else if(line == "#pragma openspace insert TRANSFERFUNC") { + line = padGeneratedString(openspaceTransferFunction()); + } + source += line + "\n"; + } + } + fragmentShaderFile.close(); + + std::ofstream fragmentShaderOut(_fragmentShaderPath); + fragmentShaderOut << source; + fragmentShaderOut.close(); +} + +std::string ABuffer::openspaceHeaders() { + + std::string headers; + headers += "#define MAX_VOLUMES " + std::to_string(_samplers.size()) + "\n"; + headers += "#define MAX_TF " + std::to_string(_transferFunctions.size()) + "\n"; + + + for (int i = 0; i < _volumes.size(); ++i) { + headers += "uniform sampler3D " + _volumes.at(i).first + ";\n"; + } + for (int i = 0; i < _transferFunctions.size(); ++i) { + headers += "uniform sampler1D " + _transferFunctions.at(i).first + ";\n"; + } + + for (int i = 0; i < _samplers.size(); ++i) { + auto found = _samplers.at(i).find_first_of('{'); + if(found!=std::string::npos) { + headers += _samplers.at(i).substr(0, found) + ";\n"; + } + } + + if(_volumes.size() < 1) + return headers; + + size_t maxLoop = 0; + headers += "const vec3 volume_dim[] = {\n"; + for (int i = 0; i < _volumes.size(); ++i) { + glm::size3_t size = _volumes.at(i).second->dimensions(); + for(int k = 0; k < 3; ++k) + maxLoop = glm::max(maxLoop, size[k]); + headers += " vec3(" + std::to_string(size[0]) + ".0," + std::to_string(size[1]) + ".0," + + std::to_string(size[2]) + ".0),\n"; + } + headers += "};\n"; + + headers += "#define LOOP_LIMIT " + std::to_string(maxLoop) + "\n"; + + headers += "float volumeStepSize[] = {\n"; + for (int i = 0; i < _volumes.size(); ++i) { + glm::size3_t size = _volumes.at(i).second->dimensions(); + headers += " stepSize,\n"; + } + headers += "};\n"; + + headers += "float volumeStepSizeOriginal[] = {\n"; + for (int i = 0; i < _volumes.size(); ++i) { + glm::size3_t size = _volumes.at(i).second->dimensions(); + headers += " stepSize,\n"; + } + headers += "};\n"; + + return headers; +} + +std::string ABuffer::openspaceSamplerCalls() { + std::string samplercalls; + for (int i = 0; i < _samplers.size(); ++i) { + + auto found1 = _samplers.at(i).find_first_not_of("vec4 "); + auto found2 = _samplers.at(i).find_first_of("(",found1); + if(found1 != std::string::npos && found2 != std::string::npos) { + std::string functionName = _samplers.at(i).substr(found1, found2 - found1); + samplercalls += "#ifndef SKIP_VOLUME_"+std::to_string(i)+"\n"; + samplercalls += "if((currentVolumeBitmask & (1 << " + std::to_string(i) + ")) == "+std::to_string(1 << i)+") {\n"; + samplercalls += " vec4 c = " + functionName + "(final_color,volume_position[" + std::to_string(i) + "]);\n"; + // samplercalls += " if(c.a < 0.1) { \n"; + // samplercalls += " if( volumeStepSize[" + std::to_string(i) + "] < 16.0*volumeStepSizeOriginal[" + std::to_string(i) + "]) \n"; + // samplercalls += " volumeStepSize[" + std::to_string(i) + "] *= 2.0; \n"; + // samplercalls += " } else {\n"; + // samplercalls += " //volume_position[" + std::to_string(i) + "] -= volume_direction[" + std::to_string(i) + "]*volumeStepSize[" + std::to_string(i) + "];\n"; + // samplercalls += " volumeStepSize[" + std::to_string(i) + "] = volumeStepSizeOriginal[" + std::to_string(i) + "]; \n"; + // samplercalls += " //c = " + functionName + "(final_color,volume_position[" + std::to_string(i) + "]);\n"; + // samplercalls += " } \n"; + // samplercalls += " if(c.a > EPSILON)\n"; + samplercalls += " blendStep(final_color, c, volumeStepSize[" + std::to_string(i) + "]);\n"; + // samplercalls += " blendStep(final_color, c, stepSize);\n"; + // samplercalls += " float aaa = volume_length[i]/myMaxSteps;\n"; + samplercalls += " volume_position[" + std::to_string(i) + "] += volume_direction[" + std::to_string(i) + "]*volumeStepSize[" + std::to_string(i) + "];\n"; + // float aaa = ray[v].w/myMaxSteps; + // pos[v] += vec4(ray[v].xyz*vec3(aaa),aaa); + // samplercalls += " volume_position[" + std::to_string(i) + "] += volume_direction[" + std::to_string(i) + "]*volumeStepSize[" + std::to_string(i) + "];\n"; + samplercalls += "}\n"; + samplercalls += "#endif\n"; + } + + + } + return samplercalls; +} + +std::string ABuffer::openspaceSamplers() { + std::string samplers; + for (int i = 0; i < _samplers.size(); ++i) { + samplers += _samplers.at(i) + "\n"; + } + return samplers; +} + +std::string ABuffer::openspaceTransferFunction() { + std::string tf; + tf += "float showfunc_size = 20.0;\n"; + tf += "float SCREEN_HEIGHTf = float(SCREEN_HEIGHT);\n"; + tf += "float SCREEN_WIDTHf = float(SCREEN_WIDTH);\n"; + for(int i = 0; i < _transferFunctions.size(); ++i) { + tf += "if( gl_FragCoord.y > SCREEN_HEIGHTf-showfunc_size*"+std::to_string(i+1)+ + " && gl_FragCoord.y < SCREEN_HEIGHTf-showfunc_size*"+std::to_string(i)+") {\n"; + tf += " float normalizedIntensity = gl_FragCoord.x / (SCREEN_WIDTHf-1) ;\n"; + tf += " vec4 tfc = texture("+ _transferFunctions.at(i).first +", normalizedIntensity);\n"; + tf += " final_color = tfc;\n"; + tf += " float cmpf = SCREEN_HEIGHTf-showfunc_size*"+std::to_string(i+1)+" + tfc.a*showfunc_size;\n"; + tf += " if(gl_FragCoord.y > cmpf) {\n"; + tf += " final_color = vec4(0,0,0,0);\n"; + tf += " } else {\n"; + tf += " final_color.a = 1.0;\n"; + tf += " }\n"; + tf += "} else if(ceil(gl_FragCoord.y) == SCREEN_HEIGHTf - showfunc_size*"+std::to_string(i+1)+") {\n"; + tf += " const float intensity = 0.4;\n"; + tf += " final_color = vec4(intensity,intensity,intensity,1.0);\n"; + tf += "}\n"; + } + + return tf; +} + + +} // openspace \ No newline at end of file diff --git a/src/abuffer/abufferSingleLinked.cpp b/src/abuffer/abufferSingleLinked.cpp new file mode 100644 index 0000000000..f1a09b3c2d --- /dev/null +++ b/src/abuffer/abufferSingleLinked.cpp @@ -0,0 +1,124 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +#include +#include + +#include +#include +#include + +#define MAX_LAYERS 10 + +namespace { + std::string _loggerCat = "ABufferSingleLinked"; +} + +namespace openspace { + +ABufferSingleLinked::ABufferSingleLinked(): _data(0), _anchorPointerTexture(0), + _anchorPointerTextureInitializer(0), _atomicCounterBuffer(0), _fragmentBuffer(0), + _fragmentTexture(0) +{} + +ABufferSingleLinked::~ABufferSingleLinked() { + if(_data != 0) + delete _data; + + glDeleteTextures(1,&_anchorPointerTexture); + glDeleteTextures(1,&_fragmentTexture); + glDeleteBuffers(1,&_anchorPointerTextureInitializer); + glDeleteBuffers(1,&_atomicCounterBuffer); + glDeleteBuffers(1,&_anchorPointerTextureInitializer); +} + +bool ABufferSingleLinked::initialize() { + // ============================ + // BUFFERS + // ============================ + glGenTextures(1, &_anchorPointerTexture); + glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + + glGenBuffers(1, &_anchorPointerTextureInitializer); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, _totalPixels * sizeof(GLuint), NULL, GL_STATIC_DRAW); + + _data = (GLuint*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + memset(_data, 0x00, _totalPixels * sizeof(GLuint)); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + glGenBuffers(1, &_atomicCounterBuffer); + glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, _atomicCounterBuffer); + glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_COPY); + + glGenBuffers(1, &_fragmentBuffer); + glBindBuffer(GL_TEXTURE_BUFFER, _fragmentBuffer); + glBufferData(GL_TEXTURE_BUFFER, MAX_LAYERS*_totalPixels*sizeof(GLfloat)*4, NULL, GL_DYNAMIC_COPY); + + glGenTextures(1, &_fragmentTexture); + glBindTexture(GL_TEXTURE_BUFFER, _fragmentTexture); + glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, _fragmentBuffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + + glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI); + + return initializeABuffer(); +} + +void ABufferSingleLinked::clear() { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); + glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + static const GLuint zero = 1; + glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, _atomicCounterBuffer); + glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(zero), &zero); + glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, 0); +} + +void ABufferSingleLinked::preRender() { + + // Bind head-pointer image for read-write + glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, _atomicCounterBuffer); + glBindImageTexture(0, _anchorPointerTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI); + glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI); +} + +void ABufferSingleLinked::postRender() { + +} + +std::string ABufferSingleLinked::settings() { + return R"()"; +} + + +} // openspace \ No newline at end of file diff --git a/src/abuffer/abufferdynamic.cpp b/src/abuffer/abufferdynamic.cpp new file mode 100644 index 0000000000..8943905eda --- /dev/null +++ b/src/abuffer/abufferdynamic.cpp @@ -0,0 +1,124 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +#include +#include + +#include +#include +#include + +#define MAX_LAYERS 10 + +namespace { + std::string _loggerCat = "ABufferDynamic"; +} + +namespace openspace { + +ABufferDynamic::ABufferDynamic(): _data(0), _anchorPointerTexture(0), + _anchorPointerTextureInitializer(0), _atomicCounterBuffer(0), _fragmentBuffer(0), + _fragmentTexture(0) +{} + +ABufferDynamic::~ABufferDynamic() { + if(_data != 0) + delete _data; + + glDeleteTextures(1,&_anchorPointerTexture); + glDeleteTextures(1,&_fragmentTexture); + glDeleteBuffers(1,&_anchorPointerTextureInitializer); + glDeleteBuffers(1,&_atomicCounterBuffer); + glDeleteBuffers(1,&_anchorPointerTextureInitializer); +} + +bool ABufferDynamic::initialize() { + // ============================ + // BUFFERS + // ============================ + glGenTextures(1, &_anchorPointerTexture); + glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + + glGenBuffers(1, &_anchorPointerTextureInitializer); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, _totalPixels * sizeof(GLuint), NULL, GL_STATIC_DRAW); + + _data = (GLuint*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + memset(_data, 0x00, _totalPixels * sizeof(GLuint)); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + glGenBuffers(1, &_atomicCounterBuffer); + glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, _atomicCounterBuffer); + glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_COPY); + + glGenBuffers(1, &_fragmentBuffer); + glBindBuffer(GL_TEXTURE_BUFFER, _fragmentBuffer); + glBufferData(GL_TEXTURE_BUFFER, MAX_LAYERS*_totalPixels*sizeof(GLfloat)*4, NULL, GL_DYNAMIC_COPY); + + glGenTextures(1, &_fragmentTexture); + glBindTexture(GL_TEXTURE_BUFFER, _fragmentTexture); + glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, _fragmentBuffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + + glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI); + + return initializeABuffer(); +} + +void ABufferDynamic::clear() { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); + glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + static const GLuint zero = 1; + glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, _atomicCounterBuffer); + glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(zero), &zero); + glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, 0); +} + +void ABufferDynamic::preRender() { + + // Bind head-pointer image for read-write + glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, _atomicCounterBuffer); + glBindImageTexture(0, _anchorPointerTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI); + glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI); +} + +void ABufferDynamic::postRender() { + +} + +std::string ABufferDynamic::settings() { + return R"(#define ABUFFER_SINGLE_LINKED)"; +} + + +} // openspace \ No newline at end of file diff --git a/src/abuffer/abufferfixed.cpp b/src/abuffer/abufferfixed.cpp new file mode 100644 index 0000000000..36c5a7aeae --- /dev/null +++ b/src/abuffer/abufferfixed.cpp @@ -0,0 +1,137 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +#include +#include + +#include +#include +#include + +#define MAX_LAYERS 32 + +namespace { + std::string _loggerCat = "ABufferFixed"; +} + +namespace openspace { + +ABufferFixed::ABufferFixed(): _data(0), _anchorPointerTexture(0), + _anchorPointerTextureInitializer(0), _atomicCounterBuffer(0), _fragmentBuffer(0), + _fragmentTexture(0) +{} + +ABufferFixed::~ABufferFixed() { + if(_data != 0) + delete _data; + + glDeleteTextures(1,&_anchorPointerTexture); + glDeleteTextures(1,&_fragmentTexture); + // glDeleteTextures(1,&_atomicCounterTexture); + glDeleteBuffers(1,&_anchorPointerTextureInitializer); + // glDeleteBuffers(1,&_atomicCounterBuffer); + glDeleteBuffers(1,&_anchorPointerTextureInitializer); +} + +bool ABufferFixed::initialize() { + // ============================ + // BUFFERS + // ============================ + glGenTextures(1, &_anchorPointerTexture); + glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + + glGenBuffers(1, &_anchorPointerTextureInitializer); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); + glBufferData(GL_PIXEL_UNPACK_BUFFER, _totalPixels * sizeof(GLuint), NULL, GL_STATIC_DRAW); + + _data = (GLuint*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + memset(_data, 0x00, _totalPixels * sizeof(GLuint)); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + + // glGenBuffers(1, &_atomicCounterBuffer); + // glBindBuffer(GL_TEXTURE_BUFFER, _atomicCounterBuffer); + // glBufferData(GL_TEXTURE_BUFFER, _totalPixels*sizeof(GLuint), NULL, GL_DYNAMIC_COPY); + + // glGenTextures(1, &_atomicCounterTexture); + // glBindTexture(GL_TEXTURE_2D, _atomicCounterTexture); + // glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, _atomicCounterBuffer); + // glBindTexture(GL_TEXTURE_BUFFER, 0); + + + glGenBuffers(1, &_fragmentBuffer); + glBindBuffer(GL_TEXTURE_BUFFER, _fragmentBuffer); + glBufferData(GL_TEXTURE_BUFFER, MAX_LAYERS*_totalPixels*sizeof(GLfloat)*4, NULL, GL_DYNAMIC_COPY); + + glGenTextures(1, &_fragmentTexture); + glBindTexture(GL_TEXTURE_BUFFER, _fragmentTexture); + glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, _fragmentBuffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + + glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI); + + return initializeABuffer(); +} + +void ABufferFixed::clear() { + + // Bind texture initializer + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _anchorPointerTextureInitializer); + + // clear _anchorPointerTexture + glBindTexture(GL_TEXTURE_2D, _anchorPointerTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + + // // clear _atomicCounterTexture + // glBindTexture(GL_TEXTURE_2D, _atomicCounterTexture); + // glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, _width, _height, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL); + + // reset GL_PIXEL_UNPACK_BUFFER + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + +} + +void ABufferFixed::preRender() { + + // Bind head-pointer image for read-write + glBindImageTexture(0, _anchorPointerTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI); + glBindImageTexture(1, _fragmentTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI); + // glBindImageTexture(2, _atomicCounterTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI); +} + +void ABufferFixed::postRender() { + +} + +std::string ABufferFixed::settings() { + return R"()"; +} + + +} // openspace \ No newline at end of file diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index e51191af36..6d0a9d518c 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -31,10 +31,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -43,42 +45,59 @@ #include #include #include -#include +#include using namespace ghoul::filesystem; using namespace ghoul::logging; +using namespace openspace::scripting; + namespace { const std::string _loggerCat = "OpenSpaceEngine"; const std::string _configurationFile = "openspace.cfg"; const std::string _basePathToken = "${BASE_PATH}"; const std::string _sgctDefaultConfigFile = "${SGCT}/single.xml"; + + const std::string _sgctConfigArgumentCommand = "-config"; + + struct { + std::string configurationName; + } commandlineArgumentPlaceholders; } +using namespace ghoul::cmdparser; + namespace openspace { OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; -OpenSpaceEngine::OpenSpaceEngine() - : _configurationManager(nullptr) - , _interactionHandler(nullptr) - , _renderEngine(nullptr) -//, _scriptEngine(nullptr) +OpenSpaceEngine::OpenSpaceEngine(std::string programName) + : _configurationManager(new ghoul::Dictionary) + , _interactionHandler(new InteractionHandler) + , _renderEngine(new RenderEngine) + , _scriptEngine(new ScriptEngine) + , _commandlineParser(new CommandlineParser(programName, true)) { } OpenSpaceEngine::~OpenSpaceEngine() { delete _configurationManager; + _configurationManager = nullptr; delete _interactionHandler; + _interactionHandler = nullptr; delete _renderEngine; + _renderEngine = nullptr; + delete _scriptEngine; + _scriptEngine = nullptr; + delete _commandlineParser; + _commandlineParser = nullptr; - // TODO deallocate script engine when starting to use it - // delete _scriptEngine; - + SpiceManager::deinitialize(); Spice::deinit(); - Time::deinit(); + Time::deinitialize(); DeviceIdentifier::deinit(); + FileSystem::deinitialize(); LogManager::deinitialize(); } @@ -87,6 +106,18 @@ OpenSpaceEngine& OpenSpaceEngine::ref() assert(_engine); return *_engine; } + +bool OpenSpaceEngine::gatherCommandlineArguments() +{ + // TODO: Get commandline arguments from all modules + + CommandlineCommand* configurationFileCommand = new SingleCommand( + &commandlineArgumentPlaceholders.configurationName, "-config", "-c", + "Provides the path to the OpenSpace configuration file"); + _commandlineParser->addCommand(configurationFileCommand); + + return true; +} void OpenSpaceEngine::registerPathsFromDictionary(const ghoul::Dictionary& dictionary) { @@ -97,10 +128,12 @@ void OpenSpaceEngine::registerPathsFromDictionary(const ghoul::Dictionary& dicti const std::string fullKey = ghoul::filesystem::FileSystem::TokenOpeningBraces + key + ghoul::filesystem::FileSystem::TokenClosingBraces; - LDEBUG(fullKey << ": " << p); + LDEBUG("Registering path " << fullKey << ": " << p); bool override = (_basePathToken == fullKey); + if (override) + LINFO("Overriding base path with '" << p << "'"); FileSys.registerPathToken(fullKey, p, override); } } @@ -118,7 +151,6 @@ bool OpenSpaceEngine::registerBasePathFromConfigurationFile(const std::string& f if (last == std::string::npos) return false; - std::string basePath = absolutePath.substr(0, last); FileSys.registerPathToken(_basePathToken, basePath); @@ -128,88 +160,117 @@ bool OpenSpaceEngine::registerBasePathFromConfigurationFile(const std::string& f bool OpenSpaceEngine::findConfiguration(std::string& filename) { - if (!filename.empty()) - return FileSys.fileExists(filename); - else { - std::string currentDirectory = FileSys.absolutePath(FileSys.currentDirectory()); - size_t occurrences = std::count(currentDirectory.begin(), currentDirectory.end(), - ghoul::filesystem::FileSystem::PathSeparator); + std::string currentDirectory = FileSys.absolutePath(FileSys.currentDirectory()); + size_t occurrences = std::count(currentDirectory.begin(), currentDirectory.end(), + ghoul::filesystem::FileSystem::PathSeparator); - std::string cfgname = _configurationFile; + std::string cfgname = _configurationFile; - bool cfgFileFound = false; - for (size_t i = 0; i < occurrences; ++i) { - if (i > 0) - cfgname = "../" + cfgname; - if (FileSys.fileExists(cfgname)) { - cfgFileFound = true; - break; - } + bool cfgFileFound = false; + for (size_t i = 0; i < occurrences; ++i) { + if (i > 0) + cfgname = "../" + cfgname; + if (FileSys.fileExists(cfgname)) { + cfgFileFound = true; + break; } - if (!cfgFileFound) - return false; - - filename = cfgname; - - return true; } + if (!cfgFileFound) + return false; + + filename = cfgname; + + return true; } -void OpenSpaceEngine::create(int argc, char** argv, +bool OpenSpaceEngine::create(int argc, char** argv, std::vector& sgctArguments) { // TODO custom assert (ticket #5) assert(_engine == nullptr); - // initialize ghoul logging + // initialize Ghoul logging LogManager::initialize(LogManager::LogLevel::Debug, true); LogMgr.addLog(new ConsoleLog); - // TODO change so initialize is not called in the create function + + // Initialize FileSystem ghoul::filesystem::FileSystem::initialize(); - - // TODO parse arguments if filename is specified, if not use default - std::string configurationFilePath = ""; - - LDEBUG("Finding configuration"); - if (!OpenSpaceEngine::findConfiguration(configurationFilePath)) { - LFATAL("Could not find OpenSpace configuration file!"); - assert(false); + + + // Sanity check of values + if (argc < 1) { + LFATAL("No arguments were passed to the function"); + return false; } + + // create other objects + LDEBUG("Creating OpenSpaceEngine"); + _engine = new OpenSpaceEngine(std::string(argv[0])); + + + // Query modules for commandline arguments + const bool gatherSuccess = _engine->gatherCommandlineArguments(); + if (!gatherSuccess) + return false; + - LINFO(FileSys.absolutePath(configurationFilePath)); - - // create objects - _engine = new OpenSpaceEngine; - _engine->_renderEngine = new RenderEngine; - _engine->_interactionHandler = new InteractionHandler; - _engine->_configurationManager = new ghoul::Dictionary; + // Parse commandline arguments + std::vector remainingArguments; + _engine->_commandlineParser->setCommandLine(argc, argv, &sgctArguments); + const bool executeSuccess = _engine->_commandlineParser->execute(); + if (!executeSuccess) + return false; + + + // Find configuration + std::string configurationFilePath = commandlineArgumentPlaceholders.configurationName; + if (configurationFilePath.empty()) { + LDEBUG("Finding configuration"); + const bool findConfigurationSuccess = OpenSpaceEngine::findConfiguration(configurationFilePath); + if (!findConfigurationSuccess) { + LFATAL("Could not find OpenSpace configuration file!"); + return false; + } + } + LINFO("Configuration Path: '" << FileSys.absolutePath(configurationFilePath) << "'"); + // Registering base path LDEBUG("Registering base path"); if (!OpenSpaceEngine::registerBasePathFromConfigurationFile(configurationFilePath)) { LFATAL("Could not register base path"); - assert(false); + return false; } - ghoul::Dictionary& configuration = *(_engine->_configurationManager); + + // Loading configuration from disk + LDEBUG("Loading configuration from disk"); + ghoul::Dictionary& configuration = _engine->configurationManager(); ghoul::lua::loadDictionaryFromFile(configurationFilePath, configuration); - if (configuration.hasKey(constants::openspaceengine::keyPaths)) { - ghoul::Dictionary pathsDictionary; - if (configuration.getValue(constants::openspaceengine::keyPaths, pathsDictionary)) - OpenSpaceEngine::registerPathsFromDictionary(pathsDictionary); + ghoul::Dictionary pathsDictionary; + const bool success = configuration.getValueSafe(constants::openspaceengine::keyPaths, pathsDictionary); + if (success) + OpenSpaceEngine::registerPathsFromDictionary(pathsDictionary); + else { + LFATAL("Configuration file does not contain paths token '" << constants::openspaceengine::keyPaths << "'"); + return false; } - std::string sgctConfigurationPath = _sgctDefaultConfigFile; - if (configuration.hasKey(constants::openspaceengine::keyConfigSgct)) - configuration.getValue(constants::openspaceengine::keyConfigSgct, sgctConfigurationPath); - - sgctArguments.push_back(argv[0]); - sgctArguments.push_back("-config"); - sgctArguments.push_back(absPath(sgctConfigurationPath)); - - for (int i = 1; i < argc; ++i) - sgctArguments.push_back(argv[i]); + + // Determining SGCT configuration file + LDEBUG("Determining SGCT configuration file"); + std::string sgctConfigurationPath = _sgctDefaultConfigFile; + configuration.getValueSafe(constants::openspaceengine::keyConfigSgct, + sgctConfigurationPath); + + // Prepend the outgoing sgctArguments with the program name + // as well as the configuration file that sgct is supposed to use + sgctArguments.insert(sgctArguments.begin(), argv[0]); + sgctArguments.insert(sgctArguments.begin() + 1, _sgctConfigArgumentCommand); + sgctArguments.insert(sgctArguments.begin() + 2, absPath(sgctConfigurationPath)); + + return true; } void OpenSpaceEngine::destroy() @@ -230,14 +291,25 @@ bool OpenSpaceEngine::initialize() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); GLFWwindow* win = sgct::Engine::instance()->getActiveWindowPtr()->getWindowHandle(); glfwSwapBuffers(win); + //int samples = sqrt(sgct::Engine::instance()->getActiveWindowPtr()->getNumberOfAASamples()); + //LDEBUG("samples: " << samples); + + int x1, xSize, y1, ySize; + sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); + std::string sourceHeader = ""; + sourceHeader += "#define SCREEN_WIDTH " + std::to_string(xSize) + "\n"; + sourceHeader += "#define SCREEN_HEIGHT " + std::to_string(ySize) + "\n"; + sourceHeader += "#define ABUFFER_SINGLE_LINKED " + std::to_string(ABUFFER_SINGLE_LINKED) + "\n"; + sourceHeader += "#define ABUFFER_FIXED " + std::to_string(ABUFFER_FIXED) + "\n"; + sourceHeader += "#define ABUFFER_DYNAMIC " + std::to_string(ABUFFER_DYNAMIC) + "\n"; + sourceHeader += "#define ABUFFER_IMPLEMENTATION " + std::to_string(ABUFFER_IMPLEMENTATION) + "\n"; + _shaderBuilder.createSourceFile(true); + _shaderBuilder.sourceFileHeader(sourceHeader); // Register the filepaths from static function enables easy testing // registerFilePaths(); _context.createContextFromGLContext(); - // initialize the configurationmanager with the default configuration - //_configurationManager->loadConfiguration(absPath("${SCRIPTS}/DefaultConfig.lua")); - // Detect and log OpenCL and OpenGL versions and available devices ghoul::systemcapabilities::SystemCapabilities::initialize(); SysCap.addComponent(new ghoul::systemcapabilities::CPUCapabilitiesComponent); @@ -246,34 +318,48 @@ bool OpenSpaceEngine::initialize() SysCap.detectCapabilities(); SysCap.logCapabilities(); + std::string timeKernel; + OsEng.configurationManager().getValueSafe(constants::openspaceengine::keyConfigTimekernel, timeKernel); + // initialize OpenSpace helpers - Time::init(); + SpiceManager::initialize(); + Time::initialize(timeKernel); Spice::init(); Spice::ref().loadDefaultKernels(); FactoryManager::initialize(); + + scriptEngine().initialize(); + + // Register Lua script functions + LDEBUG("Registering Lua libraries"); + scriptEngine().addLibrary(SceneGraph::luaLibrary()); + scriptEngine().addLibrary(Time::luaLibrary()); + // Load scenegraph SceneGraph* sceneGraph = new SceneGraph; _renderEngine->setSceneGraph(sceneGraph); - if (!OsEng.configurationManager().hasValue( - constants::openspaceengine::keyConfigScene)) { - LFATAL("Configuration needs to point to the scene file"); + + std::string sceneDescriptionPath; + bool success = OsEng.configurationManager().getValueSafe( + constants::openspaceengine::keyConfigScene, sceneDescriptionPath); + if (!success) { + LFATAL("The configuration does not contain a scene file under key '" << + constants::openspaceengine::keyConfigScene << "'"); return false; } - std::string sceneDescriptionPath; - bool success = _configurationManager->getValue( - constants::openspaceengine::keyConfigScene, sceneDescriptionPath); - - if (!FileSys.fileExists(sceneDescriptionPath)) { - LFATAL("Could not find '" << sceneDescriptionPath << "'"); + if (!FileSys.fileExists(sceneDescriptionPath)) { + LFATAL("Could not find scene description '" << sceneDescriptionPath << "'"); return false; } std::string scenePath; - success = _configurationManager->getValue(constants::openspaceengine::keyPathScene, scenePath); + success = _configurationManager->getValueSafe( + constants::openspaceengine::keyPathScene, scenePath); if (!success) { - LFATAL("Could not find SCENEPATH key in configuration file"); + LFATAL("Could not find key '" << constants::openspaceengine::keyPathScene << + "' in configuration file '" << sceneDescriptionPath << "'"); return false; } @@ -281,7 +367,6 @@ bool OpenSpaceEngine::initialize() _renderEngine->initialize(); sceneGraph->loadScene(sceneDescriptionPath, scenePath); sceneGraph->initialize(); - _renderEngine->setSceneGraph(sceneGraph); #ifdef FLARE_ONLY _flare = new Flare(); @@ -293,13 +378,42 @@ bool OpenSpaceEngine::initialize() DeviceIdentifier::ref().scanDevices(); _engine->_interactionHandler->connectDevices(); + // Run start up scripts + //using ghoul::Dictionary; + //using constants::openspaceengine::keyStartupScript; + ghoul::Dictionary scripts; + success = _engine->configurationManager().getValueSafe( + constants::openspaceengine::keyStartupScript, scripts); + if (success) { + for (size_t i = 0; i < scripts.size(); ++i) { + std::stringstream stream; + // Dictionary-size is 0-based; script numbers are 1-based + stream << (i + 1); + const std::string& key = stream.str(); + const bool hasKey = scripts.hasKeyAndValue(key); + if (!hasKey) { + LERROR("The startup scripts have to be declared in a simple array format"); + break; + } + + std::string scriptPath; + scripts.getValue(key, scriptPath); + std::string&& absoluteScriptPath = absPath(scriptPath); + _engine->scriptEngine().runScriptFile(absoluteScriptPath); + } + } + +#ifdef OPENSPACE_VIDEO_EXPORT + LINFO("OpenSpace compiled with video export; press Print Screen to start/stop recording"); +#endif + return true; } ghoul::Dictionary& OpenSpaceEngine::configurationManager() { // TODO custom assert (ticket #5) - assert(_configurationManager != nullptr); + assert(_configurationManager); return *_configurationManager; } @@ -311,17 +425,31 @@ ghoul::opencl::CLContext& OpenSpaceEngine::clContext() InteractionHandler& OpenSpaceEngine::interactionHandler() { // TODO custom assert (ticket #5) - assert(_configurationManager != nullptr); + assert(_interactionHandler); return *_interactionHandler; } RenderEngine& OpenSpaceEngine::renderEngine() { // TODO custom assert (ticket #5) - assert(_configurationManager != nullptr); + assert(_renderEngine); return *_renderEngine; } +ScriptEngine& OpenSpaceEngine::scriptEngine() +{ + // TODO custom assert (ticket #5) + assert(_scriptEngine); + return *_scriptEngine; +} + + +ShaderCreator& OpenSpaceEngine::shaderBuilder() +{ + // TODO custom assert (ticket #5) + return _shaderBuilder; +} + bool OpenSpaceEngine::initializeGL() { return _renderEngine->initializeGL(); @@ -338,6 +466,8 @@ void OpenSpaceEngine::preSynchronization() _interactionHandler->update(dt); _interactionHandler->lockControls(); + + Time::ref().advanceTime(dt); } #ifdef FLARE_ONLY _flare->preSync(); @@ -366,6 +496,17 @@ void OpenSpaceEngine::postDraw() if (sgct::Engine::instance()->isMaster()) { _interactionHandler->unlockControls(); } +#ifdef OPENSPACE_VIDEO_EXPORT + float speed = 0.01; + glm::vec3 euler(0.0, speed, 0.0); + glm::quat rot = glm::quat(euler); + glm::vec3 euler2(0.0, -speed, 0.0); + glm::quat rot2 = glm::quat(euler2); + _interactionHandler->orbit(rot); + _interactionHandler->rotate(rot2); + if(_doVideoExport) + sgct::Engine::instance()->takeScreenshot(); +#endif #ifdef FLARE_ONLY _flare->postDraw(); #endif @@ -376,6 +517,12 @@ void OpenSpaceEngine::keyboardCallback(int key, int action) if (sgct::Engine::instance()->isMaster()) { _interactionHandler->keyboardCallback(key, action); } +#ifdef OPENSPACE_VIDEO_EXPORT + // LDEBUG("key: " << key); + // LDEBUG("SGCT_KEY_PRINT_SCREEN: " << SGCT_KEY_PRINT_SCREEN); + if(action == SGCT_PRESS && key == SGCT_KEY_PRINT_SCREEN) + _doVideoExport = !_doVideoExport; +#endif #ifdef FLARE_ONLY _flare->keyboard(key, action); #endif @@ -431,4 +578,24 @@ void OpenSpaceEngine::decode() #endif } +void OpenSpaceEngine::externalControlCallback(const char* receivedChars, + int size, int clientId) +{ + if (size == 0) + return; + + // The first byte determines the type of message + const char type = receivedChars[0]; + switch (type) { + case '0': // LuaScript + { + std::string script = std::string(receivedChars + 1); + LINFO("Received Lua Script: '" << script << "'"); + _scriptEngine->runScript(script); + } + } + + +} + } // namespace openspace diff --git a/src/flare/CLProgram.cpp b/src/flare/CLProgram.cpp index 1012c0dd9a..3e0d102798 100644 --- a/src/flare/CLProgram.cpp +++ b/src/flare/CLProgram.cpp @@ -2,6 +2,7 @@ * Author: Victor Sand (victor.sand@gmail.com) * */ + //#include #include #include @@ -248,14 +249,13 @@ bool CLProgram::ReleaseBuffer(unsigned int _argNr) { bool CLProgram::PrepareProgram() { //ghoulFinishGL(); -/* -#ifdef __APPLE__ +//#ifdef __APPLE__ //glFlushRenderAPPLE(); - glFinish(); + // glFinish(); //glFlush(); -#else -*/ + //#else + glFinish(); // Let OpenCL take control of the shared GL textures @@ -341,15 +341,13 @@ bool CLProgram::FinishProgram() { LERROR("Failed to finish program"); return false; } - /* -#else - error_ = clFinish(clManager_->commandQueues_[CLManager::EXECUTE]); - if (!clManager_->CheckSuccess(error_, "FinishProgram, clFinish")) { - ERROR("Failed to finish program"); - return false; - } -#endif -*/ + //#else + //error_ = clFinish(clManager_->commandQueues_[CLManager::EXECUTE]); + //if (!clManager_->CheckSuccess(error_, "FinishProgram, clFinish")) { + // ERROR("Failed to finish program"); + // return false; + //} + //#endif return true; } diff --git a/src/flare/flare.cpp b/src/flare/flare.cpp index 55243e0c2f..da196970cc 100644 --- a/src/flare/flare.cpp +++ b/src/flare/flare.cpp @@ -27,13 +27,13 @@ using namespace osp; Flare::Flare() : Renderable(ghoul::Dictionary()) + , _oldTime(0.f) + , _currentTime(0.f) , _leftMouseButton(false) , _currentMouseX(0) , _currentMouseY(0) , _lastMouseX(0) , _lastMouseY(0) - , _oldTime(0.f) - , _currentTime(0.f) { setBoundingSphere(PowerScaledScalar::CreatePSS(sqrt(3.0f))); } diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 8fb5c823e0..7f9032adf9 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -119,7 +119,7 @@ Camera * InteractionHandler::getCamera() const { const psc InteractionHandler::getOrigin() const { if(node_) - return node_->getWorldPosition(); + return node_->worldPosition(); return psc(); } @@ -155,7 +155,7 @@ void InteractionHandler::orbit(const glm::quat &rotation) { // should be changed to something more dynamic =) psc origin; if(node_) { - origin = node_->getWorldPosition(); + origin = node_->worldPosition(); } psc relative_origin_coordinate = relative - origin; @@ -173,19 +173,21 @@ void InteractionHandler::distance(const PowerScaledScalar &distance) { lockControls(); psc relative = camera_->position(); - psc origin; - if(node_) { - origin = node_->getWorldPosition(); - } + const psc origin = (node_) ? node_->worldPosition() : psc(); psc relative_origin_coordinate = relative - origin; - glm::vec3 dir(relative_origin_coordinate.direction()); - dir = dir * distance[0]; - relative_origin_coordinate = dir; + const glm::vec3 dir(relative_origin_coordinate.direction()); + glm:: vec3 newdir = dir * distance[0]; + relative_origin_coordinate = newdir; relative_origin_coordinate[3] = distance[1]; relative = relative + relative_origin_coordinate; - camera_->setPosition(relative); + relative_origin_coordinate = relative - origin; + newdir = relative_origin_coordinate.direction(); + + // update only if on the same side of the origin + if(glm::angle(newdir, dir) < 90.0f) + camera_->setPosition(relative); unlockControls(); } @@ -246,7 +248,7 @@ glm::vec3 InteractionHandler::mapToCamera(glm::vec3 trackballPos) { //Get x,y,z axis vectors of current camera view glm::vec3 currentViewYaxis = glm::normalize(camera_->lookUpVector()); - psc viewDir = camera_->position() - node_->getWorldPosition(); + psc viewDir = camera_->position() - node_->worldPosition(); glm::vec3 currentViewZaxis = glm::normalize(viewDir.vec3()); glm::vec3 currentViewXaxis = glm::normalize(glm::cross(currentViewYaxis, currentViewZaxis)); @@ -303,69 +305,63 @@ void InteractionHandler::keyboardCallback(int key, int action) { // TODO package in script const double speed = 2.75; const double dt = getDt(); - if (key == 'S') { - glm::vec3 euler(speed * dt* pow(10, 17), 0.0, 0.0); - glm::quat rot = glm::quat(euler); - orbit(rot); - } - if (key == 'W') { - glm::vec3 euler(-speed * dt* pow(10, 17), 0.0, 0.0); - glm::quat rot = glm::quat(euler); - orbit(rot); - } - if (key == 'A') { - glm::vec3 euler(0.0, -speed * dt, 0.0); - glm::quat rot = glm::quat(euler); - orbit(rot); - } - if (key == 'D') { - glm::vec3 euler(0.0, speed * dt, 0.0); - glm::quat rot = glm::quat(euler); - orbit(rot); - } - if (key == 262) { - glm::vec3 euler(0.0, speed * dt, 0.0); - glm::quat rot = glm::quat(euler); - rotate(rot); - } - if (key == 263) { - glm::vec3 euler(0.0, -speed * dt, 0.0); - glm::quat rot = glm::quat(euler); - rotate(rot); - } - if (key == 264) { - glm::vec3 euler(speed * dt, 0.0, 0.0); - glm::quat rot = glm::quat(euler); - rotate(rot); - } - if (key == 265) { - glm::vec3 euler(-speed * dt, 0.0, 0.0); - glm::quat rot = glm::quat(euler); - rotate(rot); - } - if (key == 'R') { - PowerScaledScalar dist(-speed * dt, 0.0); - distance(dist); - } - if (key == 'F') { - PowerScaledScalar dist(speed * dt, 0.0); - distance(dist); - } - if (key == 'T') { - PowerScaledScalar dist(-speed * dt, 8.0); - distance(dist); - } - if (key == 'G') { - PowerScaledScalar dist(speed * dt, 8.0); - distance(dist); - } - if (key == 'Y') { - PowerScaledScalar dist(-speed * dt, 18.0); - distance(dist); - } - if (key == 'H') { - PowerScaledScalar dist(speed * dt, 18.0); - distance(dist); + if(action == SGCT_PRESS || action == SGCT_REPEAT) { + if (key == SGCT_KEY_S) { + glm::vec3 euler(speed * dt, 0.0, 0.0); + glm::quat rot = glm::quat(euler); + orbit(rot); + } + if (key == SGCT_KEY_W) { + glm::vec3 euler(-speed * dt, 0.0, 0.0); + glm::quat rot = glm::quat(euler); + orbit(rot); + } + if (key == SGCT_KEY_A) { + glm::vec3 euler(0.0, -speed * dt, 0.0); + glm::quat rot = glm::quat(euler); + orbit(rot); + } + if (key == SGCT_KEY_D) { + glm::vec3 euler(0.0, speed * dt, 0.0); + glm::quat rot = glm::quat(euler); + orbit(rot); + } + if (key == 262) { + glm::vec3 euler(0.0, speed * dt, 0.0); + glm::quat rot = glm::quat(euler); + rotate(rot); + } + if (key == 263) { + glm::vec3 euler(0.0, -speed * dt, 0.0); + glm::quat rot = glm::quat(euler); + rotate(rot); + } + if (key == 264) { + glm::vec3 euler(speed * dt, 0.0, 0.0); + glm::quat rot = glm::quat(euler); + rotate(rot); + } + if (key == 265) { + glm::vec3 euler(-speed * dt, 0.0, 0.0); + glm::quat rot = glm::quat(euler); + rotate(rot); + } + if (key == SGCT_KEY_R) { + PowerScaledScalar dist(-speed * dt, 0.0); + distance(dist); + } + if (key == SGCT_KEY_F) { + PowerScaledScalar dist(speed * dt, 0.0); + distance(dist); + } + if (key == SGCT_KEY_T) { + PowerScaledScalar dist(-speed * 100.0 * dt, 0.0); + distance(dist); + } + if (key == SGCT_KEY_G) { + PowerScaledScalar dist(speed * 100.0 * dt, 0.0); + distance(dist); + } } /* if (key == '1') { @@ -393,15 +389,23 @@ void InteractionHandler::keyboardCallback(int key, int action) { getCamera()->setCameraDirection(glm::vec3(0.0, 0.0, -1.0)); } */ + // std::pair >::iterator, std::multimap >::iterator> ret; + if(action == SGCT_PRESS) { + auto ret = _keyCallbacks.equal_range(key); + for (auto it=ret.first; it!=ret.second; ++it) + it->second(); + } + + } void InteractionHandler::mouseButtonCallback(int key, int action) { //if(mouseControl_ != nullptr) { // mouseControl_->mouseButtonCallback(key,action); //} - if (key == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) + if (key == SGCT_MOUSE_BUTTON_LEFT && action == SGCT_PRESS) _leftMouseButtonDown = true; - else if (key == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) { + else if (key == SGCT_MOUSE_BUTTON_LEFT && action == SGCT_RELEASE) { _leftMouseButtonDown = false; _isMouseBeingPressedAndHeld = false; } @@ -420,7 +424,21 @@ void InteractionHandler::mouseScrollWheelCallback(int pos) { //if(mouseControl_ != nullptr) { // mouseControl_->mouseScrollCallback(pos); //} + const double speed = 4.75; + const double dt = getDt(); + if(pos < 0) { + PowerScaledScalar dist(speed * dt, 0.0); + distance(dist); + } else if(pos > 0) { + PowerScaledScalar dist(-speed * dt, 0.0); + distance(dist); + } } +void InteractionHandler::addKeyCallback(int key, std::function f) { + //std::map > > _keyCallbacks; + + _keyCallbacks.insert(std::make_pair(key, f)); +} } // namespace openspace diff --git a/src/interface/interface.cpp b/src/interface/interface.cpp index f2e44d1509..f7082931db 100644 --- a/src/interface/interface.cpp +++ b/src/interface/interface.cpp @@ -33,7 +33,7 @@ */ namespace openspace { -Interface::Interface(OpenSpaceEngine* engine) : _engine(engine) {} +Interface::Interface(OpenSpaceEngine* ) {} Interface::~Interface() {} void Interface::callback(const char* receivedChars) { diff --git a/src/main.cpp b/src/main.cpp index 92407ad736..ffad9cdfce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,23 +22,20 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ - // open space includes #include -#include // sgct includes #include sgct::Engine* _sgctEngine; -openspace::Interface* _interface; // function pointer declarations -void mainInitFunc(void); -void mainPreSyncFunc(void); -void mainPostSyncPreDrawFunc(void); -void mainRenderFunc(void); -void mainPostDrawFunc(void); +void mainInitFunc(); +void mainPreSyncFunc(); +void mainPostSyncPreDrawFunc(); +void mainRenderFunc(); +void mainPostDrawFunc(); void mainKeyboardCallback(int key, int action); void mainMouseButtonCallback(int key, int action); void mainMousePosCallback(double x, double y); @@ -47,27 +44,30 @@ void mainEncodeFun(); void mainDecodeFun(); void mainExternalControlCallback(const char * receivedChars, int size, int clientId); +namespace { + const std::string _loggerCat = "main"; +} + int main(int argc, char** argv) { // create the OpenSpace engine and get arguments for the sgct engine std::vector sgctArguments; - openspace::OpenSpaceEngine::create(argc, argv, sgctArguments); + const bool success = openspace::OpenSpaceEngine::create(argc, argv, sgctArguments); + if (!success) + return EXIT_FAILURE; // create sgct engine c arguments int newArgc = static_cast(sgctArguments.size()); - char** newArgv = new char* [newArgc]; - for (int i = 0; i < newArgc; ++i) { - // newArgv[i] = new char[sgctArguments.at(i).length()]; - // std::strcpy(newArgv[i], sgctArguments.at(i).c_str()); + char** newArgv = new char*[newArgc]; + for (int i = 0; i < newArgc; ++i) newArgv[i] = const_cast(sgctArguments.at(i).c_str()); - } + LDEBUG("Creating SGCT Engine"); _sgctEngine = new sgct::Engine(newArgc, newArgv); // deallocate sgct c arguments - for (int i = 0; i < newArgc; ++i) { - // delete newArgv[i]; - } + for (int i = 0; i < newArgc; ++i) + delete newArgv[i]; delete[] newArgv; // Bind functions @@ -87,11 +87,11 @@ int main(int argc, char** argv) sgct::SharedData::instance()->setEncodeFunction(mainEncodeFun); sgct::SharedData::instance()->setDecodeFunction(mainDecodeFun); - // init the interface which will handle callbacks from an external gui - _interface = new openspace::Interface(&OsEng); - // try to open a window - if (!_sgctEngine->init(sgct::Engine::OpenGL_4_3_Core_Profile)) { + LDEBUG("Initialize SGCT Engine"); + const bool initSuccess = _sgctEngine->init(sgct::Engine::OpenGL_4_3_Core_Profile); + if (!initSuccess) { + LFATAL("Initializing failed"); // could not open a window, deallocates and exits delete _sgctEngine; openspace::OpenSpaceEngine::destroy(); @@ -99,47 +99,52 @@ int main(int argc, char** argv) } // Main loop + LDEBUG("Starting rendering loop"); _sgctEngine->render(); + LDEBUG("Destroying OpenSpaceEngine"); + openspace::OpenSpaceEngine::destroy(); + // Clean up (de-allocate) + LDEBUG("Destroying SGCT Engine"); delete _sgctEngine; // Exit program - exit(EXIT_SUCCESS); + exit(EXIT_SUCCESS); } -void mainExternalControlCallback(const char* receivedChars, int size, int clientId) -{ - if (_sgctEngine->isMaster()) - _interface->callback(receivedChars); -} - -void mainInitFunc(void) +void mainInitFunc() { OsEng.initialize(); OsEng.initializeGL(); } -void mainPreSyncFunc(void) +void mainPreSyncFunc() { OsEng.preSynchronization(); } -void mainPostSyncPreDrawFunc(void) +void mainPostSyncPreDrawFunc() { OsEng.postSynchronizationPreDraw(); } -void mainRenderFunc(void) +void mainRenderFunc() { OsEng.render(); } -void mainPostDrawFunc(void) +void mainPostDrawFunc() { OsEng.postDraw(); } +void mainExternalControlCallback(const char* receivedChars, int size, int clientId) +{ + if (_sgctEngine->isMaster()) + OsEng.externalControlCallback(receivedChars, size, clientId); +} + void mainKeyboardCallback(int key, int action) { if (_sgctEngine->isMaster()) @@ -159,11 +164,11 @@ void mainMousePosCallback(double x, double y) OsEng.mousePositionCallback(static_cast(x), static_cast(y)); } -void mainMouseScrollCallback(double pos, double /*pos2*/) +void mainMouseScrollCallback(double posX, double posY) { // TODO use float instead if (_sgctEngine->isMaster()) - OsEng.mouseScrollWheelCallback(static_cast(pos)); + OsEng.mouseScrollWheelCallback(static_cast(posY)); } void mainEncodeFun() diff --git a/src/properties/matrixproperty.cpp b/src/properties/matrixproperty.cpp index 15964307ca..e6cd6a8974 100644 --- a/src/properties/matrixproperty.cpp +++ b/src/properties/matrixproperty.cpp @@ -31,144 +31,167 @@ using std::numeric_limits; namespace openspace { namespace properties { +#define DEFAULT_FROM_LUA_LAMBDA(__TYPE__) \ + [](lua_State * state, bool& success) -> __TYPE__ { \ + __TYPE__ result; \ + int number = 1; \ + for (__TYPE__::size_type i = 0; i < __TYPE__::row_size(); ++i) { \ + for (__TYPE__::size_type j = 0; j < __TYPE__::col_size(); ++j) { \ + lua_getfield(state, -1, std::to_string(number).c_str()); \ + if (lua_isnumber(state, -1) != 1) { \ + success = false; \ + return __TYPE__(0); \ + } else { \ + result[i][j] \ + = static_cast<__TYPE__::value_type>(lua_tonumber(state, -1)); \ + lua_pop(state, 1); \ + ++number; \ + } \ + } \ + } \ + success = true; \ + return result; \ + } + +#define DEFAULT_TO_LUA_LAMBDA(__TYPE__) \ + [](lua_State * state, __TYPE__ value) -> bool { \ + lua_newtable(state); \ + int number = 1; \ + for (__TYPE__::size_type i = 0; i < __TYPE__::row_size(); ++i) { \ + for (__TYPE__::size_type j = 0; j < __TYPE__::col_size(); ++j) { \ + lua_pushnumber(state, static_cast(value[i][j])); \ + lua_setfield(state, -2, std::to_string(number).c_str()); \ + ++number; \ + } \ + } \ + return true; \ + } + REGISTER_NUMERICALPROPERTY_SOURCE(Mat2Property, glm::mat2x2, glm::mat2x2(0), - glm::mat2x2(numeric_limits::lowest()), - glm::mat2x2(numeric_limits::max()), glm::mat2x2(0.01f)); + glm::mat2x2(numeric_limits::lowest()), + glm::mat2x2(numeric_limits::max()), + glm::mat2x2(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat2x2), + DEFAULT_TO_LUA_LAMBDA(glm::mat2x2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat2x3Property, glm::mat2x3, glm::mat2x3(0), - glm::mat2x3(numeric_limits::lowest()), - glm::mat2x3(numeric_limits::max()), glm::mat2x3(0.01f)); + glm::mat2x3(numeric_limits::lowest()), + glm::mat2x3(numeric_limits::max()), + glm::mat2x3(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat2x3), + DEFAULT_TO_LUA_LAMBDA(glm::mat2x3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat2x4Property, glm::mat2x4, glm::mat2x4(0), - glm::mat2x4(numeric_limits::lowest()), - glm::mat2x4(numeric_limits::max()), glm::mat2x4(0.01f)); + glm::mat2x4(numeric_limits::lowest()), + glm::mat2x4(numeric_limits::max()), + glm::mat2x4(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat2x4), + DEFAULT_TO_LUA_LAMBDA(glm::mat2x4), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat3x2Property, glm::mat3x2, glm::mat3x2(0), - glm::mat3x2(numeric_limits::lowest()), - glm::mat3x2(numeric_limits::max()), glm::mat3x2(0.01f)); + glm::mat3x2(numeric_limits::lowest()), + glm::mat3x2(numeric_limits::max()), + glm::mat3x2(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat3x2), + DEFAULT_TO_LUA_LAMBDA(glm::mat3x2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat3Property, glm::mat3x3, glm::mat3x3(0), - glm::mat3x3(numeric_limits::lowest()), - glm::mat3x3(numeric_limits::max()), glm::mat3x3(0.01f)); + glm::mat3x3(numeric_limits::lowest()), + glm::mat3x3(numeric_limits::max()), + glm::mat3x3(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat3x3), + DEFAULT_TO_LUA_LAMBDA(glm::mat3x3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat3x4Property, glm::mat3x4, glm::mat3x4(0), - glm::mat3x4(numeric_limits::lowest()), - glm::mat3x4(numeric_limits::max()), glm::mat3x4(0.01f)); + glm::mat3x4(numeric_limits::lowest()), + glm::mat3x4(numeric_limits::max()), + glm::mat3x4(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat3x4), + DEFAULT_TO_LUA_LAMBDA(glm::mat3x4), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat4x2Property, glm::mat4x2, glm::mat4x2(0), - glm::mat4x2(numeric_limits::lowest()), - glm::mat4x2(numeric_limits::max()), glm::mat4x2(0.01f)); + glm::mat4x2(numeric_limits::lowest()), + glm::mat4x2(numeric_limits::max()), + glm::mat4x2(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat4x2), + DEFAULT_TO_LUA_LAMBDA(glm::mat4x2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat4x3Property, glm::mat4x3, glm::mat4x3(0), - glm::mat4x3(numeric_limits::lowest()), - glm::mat4x3(numeric_limits::max()), glm::mat4x3(0.01f)); + glm::mat4x3(numeric_limits::lowest()), + glm::mat4x3(numeric_limits::max()), + glm::mat4x3(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat4x3), + DEFAULT_TO_LUA_LAMBDA(glm::mat4x3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(Mat4Property, glm::mat4x4, glm::mat4x4(0), - glm::mat4x4(numeric_limits::lowest()), - glm::mat4x4(numeric_limits::max()), glm::mat4x4(0.01f)); + glm::mat4x4(numeric_limits::lowest()), + glm::mat4x4(numeric_limits::max()), + glm::mat4x4(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::mat4x4), + DEFAULT_TO_LUA_LAMBDA(glm::mat4x4), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat2Property, glm::dmat2x2, glm::dmat2x2(0), - glm::dmat2x2(numeric_limits::lowest()), - glm::dmat2x2(numeric_limits::max()), glm::dmat2x2(0.01)); + glm::dmat2x2(numeric_limits::lowest()), + glm::dmat2x2(numeric_limits::max()), + glm::dmat2x2(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat2x2), + DEFAULT_TO_LUA_LAMBDA(glm::dmat2x2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat2x3Property, glm::dmat2x3, glm::dmat2x3(0), - glm::dmat2x3(numeric_limits::lowest()), - glm::dmat2x3(numeric_limits::max()), glm::dmat2x3(0.01)); + glm::dmat2x3(numeric_limits::lowest()), + glm::dmat2x3(numeric_limits::max()), + glm::dmat2x3(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat2x3), + DEFAULT_TO_LUA_LAMBDA(glm::dmat2x3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat2x4Property, glm::dmat2x4, glm::dmat2x4(0), - glm::dmat2x4(numeric_limits::lowest()), - glm::dmat2x4(numeric_limits::max()), glm::dmat2x4(0.01)); + glm::dmat2x4(numeric_limits::lowest()), + glm::dmat2x4(numeric_limits::max()), + glm::dmat2x4(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat2x4), + DEFAULT_TO_LUA_LAMBDA(glm::dmat2x4), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat3x2Property, glm::dmat3x2, glm::dmat3x2(0), - glm::dmat3x2(numeric_limits::lowest()), - glm::dmat3x2(numeric_limits::max()), glm::dmat3x2(0.01)); + glm::dmat3x2(numeric_limits::lowest()), + glm::dmat3x2(numeric_limits::max()), + glm::dmat3x2(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat3x2), + DEFAULT_TO_LUA_LAMBDA(glm::dmat3x2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat3Property, glm::dmat3x3, glm::dmat3x3(0), - glm::dmat3x3(numeric_limits::lowest()), - glm::dmat3x3(numeric_limits::max()), glm::dmat3x3(0.01)); + glm::dmat3x3(numeric_limits::lowest()), + glm::dmat3x3(numeric_limits::max()), + glm::dmat3x3(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat3x3), + DEFAULT_TO_LUA_LAMBDA(glm::dmat3x3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat3x4Property, glm::dmat3x4, glm::dmat3x4(0), - glm::dmat3x4(numeric_limits::lowest()), - glm::dmat3x4(numeric_limits::max()), glm::dmat3x4(0.01)); + glm::dmat3x4(numeric_limits::lowest()), + glm::dmat3x4(numeric_limits::max()), + glm::dmat3x4(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat3x4), + DEFAULT_TO_LUA_LAMBDA(glm::dmat3x4), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat4x2Property, glm::dmat4x2, glm::dmat4x2(0), - glm::dmat4x2(numeric_limits::lowest()), - glm::dmat4x2(numeric_limits::max()), glm::dmat4x2(0.01)); + glm::dmat4x2(numeric_limits::lowest()), + glm::dmat4x2(numeric_limits::max()), + glm::dmat4x2(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat4x2), + DEFAULT_TO_LUA_LAMBDA(glm::dmat4x2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat4x3Property, glm::dmat4x3, glm::dmat4x3(0), - glm::dmat4x3(numeric_limits::lowest()), - glm::dmat4x3(numeric_limits::max()), glm::dmat4x3(0.01)); + glm::dmat4x3(numeric_limits::lowest()), + glm::dmat4x3(numeric_limits::max()), + glm::dmat4x3(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat4x3), + DEFAULT_TO_LUA_LAMBDA(glm::dmat4x3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DMat4Property, glm::dmat4x4, glm::dmat4x4(0), - glm::dmat4x4(numeric_limits::lowest()), - glm::dmat4x4(numeric_limits::max()), glm::dmat4x4(0.01)); + glm::dmat4x4(numeric_limits::lowest()), + glm::dmat4x4(numeric_limits::max()), + glm::dmat4x4(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dmat4x4), + DEFAULT_TO_LUA_LAMBDA(glm::dmat4x4), LUA_TTABLE); - - - -//REGISTER_NUMERICALPROPERTY_SOURCE(Vec2Property, glm::vec2, glm::vec2(0), -// glm::vec2(numeric_limits::lowest()), glm::vec2(numeric_limits::max()), -// glm::vec2(0.01f)); -//REGISTER_NUMERICALPROPERTY_SOURCE(Vec3Property, glm::vec3, glm::vec3(0), -// glm::vec3(numeric_limits::lowest()), glm::vec3(numeric_limits::max()), -// glm::vec3(0.01f)); -//REGISTER_NUMERICALPROPERTY_SOURCE(Vec4Property, glm::vec4, glm::vec4(0), -// glm::vec4(numeric_limits::lowest()), glm::vec4(numeric_limits::max()), -// glm::vec4(0.01f)); -//REGISTER_NUMERICALPROPERTY_SOURCE(DVec2Property, glm::dvec2, glm::dvec2(0), -// glm::dvec2(numeric_limits::lowest()), -// glm::dvec2(numeric_limits::max()), glm::dvec2(0.01)); -//REGISTER_NUMERICALPROPERTY_SOURCE(DVec3Property, glm::dvec3, glm::dvec3(0), -// glm::dvec3(numeric_limits::lowest()), -// glm::dvec3(numeric_limits::max()), glm::dvec3(0.01)); -//REGISTER_NUMERICALPROPERTY_SOURCE(DVec4Property, glm::dvec4, glm::dvec4(0), -// glm::dvec4(numeric_limits::lowest()), -// glm::dvec4(numeric_limits::max()), glm::dvec4(0.01)); -//REGISTER_NUMERICALPROPERTY_SOURCE(IVec2Property, glm::ivec2, glm::ivec2(0), -// glm::ivec2(numeric_limits::lowest()), glm::ivec2(numeric_limits::max()), -// glm::ivec2(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(IVec3Property, glm::ivec3, glm::ivec3(0), -// glm::ivec3(numeric_limits::lowest()), glm::ivec3(numeric_limits::max()), -// glm::ivec3(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(IVec4Property, glm::ivec4, glm::ivec4(0), -// glm::ivec4(numeric_limits::lowest()), glm::ivec4(numeric_limits::max()), -// glm::ivec4(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(UVec2Property, glm::uvec2, glm::uvec2(0), -// glm::uvec2(numeric_limits::lowest()), -// glm::uvec2(numeric_limits::max()), glm::uvec2(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(UVec3Property, glm::uvec3, glm::uvec3(0), -// glm::uvec3(numeric_limits::lowest()), -// glm::uvec3(numeric_limits::max()), glm::uvec3(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(UVec4Property, glm::uvec4, glm::uvec4(0), -// glm::uvec4(numeric_limits::lowest()), -// glm::uvec4(numeric_limits::max()), glm::uvec4(1)); - - -//REGISTER_NUMERICALPROPERTY_SOURCE(CharProperty, char, char(0), -// numeric_limits::min(), numeric_limits::max(), char(1)); -////REGISTER_NUMERICALPROPERTY_SOURCE(Char16Property, char16_t, char16_t(0), -//// numeric_limits::min(), numeric_limits::max(), char16_t(1)); -////REGISTER_NUMERICALPROPERTY_SOURCE(Char32Property, char32_t, char32_t(0), -//// numeric_limits::min(), numeric_limits::max(), char32_t(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(WCharProperty, wchar_t, wchar_t(0), -// numeric_limits::min(), numeric_limits::max(), wchar_t(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(SignedCharProperty, signed char, signed char(0), -// numeric_limits::min(), numeric_limits::max(), -// signed char(0)); -//REGISTER_NUMERICALPROPERTY_SOURCE(UCharProperty, unsigned char, unsigned char(0), -// numeric_limits::min(), numeric_limits::max(), -// unsigned char(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(ShortProperty, short, short(0), -// numeric_limits::min(), numeric_limits::max(), short(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(UShortProperty, unsigned short, unsigned short(0), -// numeric_limits::min(), numeric_limits::max(), -// unsigned short(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(IntProperty, int, int(0), -// numeric_limits::min(), numeric_limits::max(), int(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(UIntProperty, unsigned int, unsigned int(0), -// numeric_limits::min(), numeric_limits::max(), -// unsigned int(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(LongProperty, long, long(0), -// numeric_limits::min(), numeric_limits::max(), long(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(ULongProperty, unsigned long, unsigned long(0), -// numeric_limits::min(), numeric_limits::max(), -// unsigned long(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(LongLongProperty, long long, long long(0), -// numeric_limits::min(), numeric_limits::max(), long long(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(ULongLongProperty, unsigned long long, -// unsigned long long(1), numeric_limits::min(), -// numeric_limits::max(), unsigned long long(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(FloatProperty, float, 0.f, -// numeric_limits::min(), numeric_limits::max(), 0.01f); -//REGISTER_NUMERICALPROPERTY_SOURCE(DoubleProperty, double, 0.0, -// numeric_limits::min(), numeric_limits::max(), 0.01); -//REGISTER_NUMERICALPROPERTY_SOURCE(LongDoubleProperty, long double, long double(0), -// numeric_limits::min(), numeric_limits::max(), -// long double(0.01f)); - - -} // namespace properties -} // namespace openspace +} // namespace properties +} // namespace openspace diff --git a/src/properties/numericalproperty.cpp b/src/properties/numericalproperty.cpp deleted file mode 100644 index 2242371adc..0000000000 --- a/src/properties/numericalproperty.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/***************************************************************************************** -* * -* OpenSpace * -* * -* Copyright (c) 2014 * -* * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this * -* software and associated documentation files (the "Software"), to deal in the Software * -* without restriction, including without limitation the rights to use, copy, modify, * -* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -* permit persons to whom the Software is furnished to do so, subject to the following * -* conditions: * -* * -* The above copyright notice and this permission notice shall be included in all copies * -* or substantial portions of the Software. * -* * -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -****************************************************************************************/ - -#include "openspace/properties/numericalproperty.h" - diff --git a/src/properties/property.cpp b/src/properties/property.cpp index a44ffc32b2..0b5004a281 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -24,13 +24,19 @@ #include "openspace/properties/property.h" +#include + namespace openspace { namespace properties { namespace { + const std::string _loggerCat = "Property"; + const std::string _metaDataKeyGuiName = "guiName"; const std::string _metaDataKeyGroup = "group"; const std::string _metaDataKeyVisible = "isVisible"; const std::string _metaDataKeyReadOnly = "isReadOnly"; + + const std::string _metaDataKeyViewPrefix = "view."; } const std::string Property::ViewOptions::Color = "color"; @@ -41,9 +47,14 @@ const std::string Property::ViewOptions::PowerScaledScalar = "powerScaledScalar" Property::Property(std::string identifier, std::string guiName) : _identifier(std::move(identifier)) - , _guiName(std::move(guiName)) { + if (_identifier.empty()) + LWARNING("Property identifier is empty"); + if (guiName.empty()) + LWARNING("Property GUI name is empty"); + setVisible(true); + _metaData.setValue(_metaDataKeyGuiName, std::move(guiName)); } Property::~Property() {} @@ -56,14 +67,28 @@ boost::any Property::get() const { return boost::any(); } +bool Property::getLua(lua_State* state) const { + return true; +} + void Property::set(boost::any value) {} +bool Property::setLua(lua_State* state) { + return true; +} + const std::type_info& Property::type() const { return typeid(void); } +int Property::typeLua() const { + return LUA_TNONE; +} + const std::string& Property::guiName() const { - return _guiName; + std::string result; + _metaData.getValueSafe(_metaDataKeyGuiName, result); + return std::move(result); } void Property::setGroupIdentifier(std::string groupId) { @@ -71,8 +96,8 @@ void Property::setGroupIdentifier(std::string groupId) { } std::string Property::groupIdentifier() const { - std::string result = ""; - _metaData.getValue(_metaDataKeyGroup, result); + std::string result; + _metaData.getValueSafe(_metaDataKeyGroup, result); return std::move(result); } @@ -80,30 +105,12 @@ void Property::setVisible(bool state) { _metaData.setValue(_metaDataKeyVisible, state); } -bool Property::isVisible() const { - bool result = false; - _metaData.getValue(_metaDataKeyVisible, result); - return result; -} - void Property::setReadOnly(bool state) { _metaData.setValue(_metaDataKeyReadOnly, state); } -bool Property::isReadOnly() const { - bool result = false; - _metaData.getValue(_metaDataKeyReadOnly, result); - return result; -} - void Property::setViewOption(std::string option, bool value) { - _metaData.setValue("view." + option, value, true); -} - -bool Property::viewOption(const std::string& option) const { - bool result = false; - _metaData.getValue("view." + option, result); - return result; + _metaData.setValue(_metaDataKeyViewPrefix + option, value, true); } const ghoul::Dictionary& Property::metaData() const { @@ -111,7 +118,7 @@ const ghoul::Dictionary& Property::metaData() const { } void Property::onChange(std::function callback) { - _onChangeCallbacks.push_back(std::move(callback)); + _onChangeCallback = std::move(callback); } @@ -125,5 +132,10 @@ void Property::setPropertyOwner(PropertyOwner* owner) _owner = owner; } +void Property::notifyListener() { + if (_onChangeCallback) + _onChangeCallback(); +} + } // namespace properties } // namespace openspace diff --git a/src/properties/propertydelegate.cpp b/src/properties/propertydelegate.cpp deleted file mode 100644 index 8c77653821..0000000000 --- a/src/properties/propertydelegate.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/***************************************************************************************** -* * -* OpenSpace * -* * -* Copyright (c) 2014 * -* * -* Permission is hereby granted, free of charge, to any person obtaining a copy of this * -* software and associated documentation files (the "Software"), to deal in the Software * -* without restriction, including without limitation the rights to use, copy, modify, * -* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * -* permit persons to whom the Software is furnished to do so, subject to the following * -* conditions: * -* * -* The above copyright notice and this permission notice shall be included in all copies * -* or substantial portions of the Software. * -* * -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * -* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * -* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * -* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * -* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * -* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * -****************************************************************************************/ - -#include "openspace/properties/propertydelegate.h" - diff --git a/src/properties/propertyowner.cpp b/src/properties/propertyowner.cpp index 19dc8bd1cc..2b1986ce1d 100644 --- a/src/properties/propertyowner.cpp +++ b/src/properties/propertyowner.cpp @@ -37,16 +37,26 @@ bool propertyLess(Property* lhs, Property* rhs) { return lhs->identifier() < rhs->identifier(); } + +bool subOwnerLess(PropertyOwner* lhs, PropertyOwner* rhs) { + return lhs->name() < rhs->name(); +} + } PropertyOwner::PropertyOwner() : _name("") { - } PropertyOwner::~PropertyOwner() { + for (Property* p : _properties) + delete p; + _properties.clear(); + for (PropertyOwner* s : _subOwners) + delete s; + _subOwners.clear(); } const std::vector& PropertyOwner::properties() const @@ -58,23 +68,76 @@ Property* PropertyOwner::property(const std::string& id) const { assert(std::is_sorted(_properties.begin(), _properties.end(), propertyLess)); + // As the _properties list is sorted, just finding the lower bound is sufficient std::vector::const_iterator it = std::lower_bound(_properties.begin(), _properties.end(), id, [](Property* prop, const std::string& str) { return prop->identifier() < str; }); - if (it == _properties.end() || (*it)->identifier() != id) + if (it == _properties.end() || (*it)->identifier() != id) { + // if we do not own the searched property, it must consist of a concatenated + // name and we can delegate it to a subowner + const size_t ownerSeparator = id.find(URISeparator); + if (ownerSeparator == std::string::npos) { + // if we do not own the property and there is no separator, it does not exist + LERROR("The identifier '" << id << "' did not exist in PropertyOwner '" << + name() << "'"); + return nullptr; + } + else { + const std::string ownerName = id.substr(0, ownerSeparator); + const std::string propertyName = id.substr(ownerSeparator + 1); + + PropertyOwner* owner = subOwner(ownerName); + if (owner == nullptr) { + LERROR("Sub PropertyOwner '" << owner + << "' did not exist for PropertyOwner '" << name() << "'"); + return nullptr; + } + else { + // Recurse into the subOwner + return owner->property(propertyName); + } + } + } + else + return *it; +} + +bool PropertyOwner::hasProperty(const std::string& id) const { + return property(id) != nullptr; +} + +const std::vector& PropertyOwner::subOwners() const { + return _subOwners; +} + +PropertyOwner* PropertyOwner::subOwner(const std::string& name) const { + assert(std::is_sorted(_subOwners.begin(), _subOwners.end(), subOwnerLess)); + + // As the _subOwners list is sorted, getting the lower bound is sufficient + std::vector::const_iterator it + = std::lower_bound(_subOwners.begin(), _subOwners.end(), name, + [](PropertyOwner* owner, const std::string& str) { + return owner->name() < str; + }); + + if (it == _subOwners.end() || (*it)->name() != name) return nullptr; else return *it; } + +bool PropertyOwner::hasSubOwner(const std::string& name) const { + return subOwner(name) != nullptr; +} void PropertyOwner::setPropertyGroupName(std::string groupID, std::string name) { _groupNames[std::move(groupID)] = std::move(name); } - + const std::string& PropertyOwner::propertyGroupName(const std::string& groupID) const { auto it = _groupNames.find(groupID); @@ -88,6 +151,7 @@ void PropertyOwner::addProperty(Property* prop) { assert(prop != nullptr); assert(std::is_sorted(_properties.begin(), _properties.end(), propertyLess)); + assert(std::is_sorted(_subOwners.begin(), _subOwners.end(), subOwnerLess)); if (prop->identifier().empty()) { LERROR("No property identifier specified"); @@ -95,6 +159,7 @@ void PropertyOwner::addProperty(Property* prop) } // See if we can find the identifier of the property to add in the properties list + // The _properties list is sorted, so getting the lower bound is sufficient std::vector::iterator it = std::lower_bound(_properties.begin(), _properties.end(), prop->identifier(), [](Property* prop, const std::string& str) { @@ -104,12 +169,22 @@ void PropertyOwner::addProperty(Property* prop) // If we found the property identifier, we need to bail out if (it != _properties.end() && (*it)->identifier() == prop->identifier()) { LERROR("Property identifier '" << prop->identifier() - << "' already present in PropertyOwner"); + << "' already present in PropertyOwner '" + << name() << "'"); return; } else { - // Otherwise we have found the correct position to add it in - _properties.insert(it, prop); - prop->setPropertyOwner(this); + // Otherwise we still have to look if there is a PropertyOwner with the same name + const bool hasOwner = hasSubOwner(prop->identifier()); + if (hasOwner) { + LERROR("Property identifier '" << prop->identifier() << "' already names a" + << "registed PropertyOwner"); + return; + } + else { + // now have found the correct position to add it in + _properties.insert(it, prop); + prop->setPropertyOwner(this); + } } } @@ -117,6 +192,48 @@ void PropertyOwner::addProperty(Property& prop) { addProperty(&prop); } + +void PropertyOwner::addPropertySubOwner(openspace::properties::PropertyOwner* owner) { + assert(owner != nullptr); + assert(std::is_sorted(_properties.begin(), _properties.end(), propertyLess)); + assert(std::is_sorted(_subOwners.begin(), _subOwners.end(), subOwnerLess)); + + if (owner->name().empty()) { + LERROR("PropertyOwner did not have a name"); + return; + } + + // See if we can find the name of the propertyowner to add using the lower bound + std::vector::iterator it + = std::lower_bound(_subOwners.begin(), _subOwners.end(), owner->name(), + [](PropertyOwner* owner, const std::string& str) { + return owner->name() < str; + }); + + // If we found the propertyowner's name, we need to bail out + if (it != _subOwners.end() && (*it)->name() == owner->name()) { + LERROR("PropertyOwner '" << owner->name() + << "' already present in PropertyOwner '" << name() << "'"); + return; + } else { + // We still need to check if the PropertyOwners name is used in a Property + const bool hasProp = hasProperty(owner->name()); + if (hasProp) { + LERROR("PropertyOwner '" << owner->name() << "'s name already names a " + << "Property"); + return; + } + else { + // Otherwise we have found the correct position to add it in + _subOwners.insert(it, owner); + } + } + +} + +void PropertyOwner::addPropertySubOwner(openspace::properties::PropertyOwner& owner) { + addPropertySubOwner(&owner); +} void PropertyOwner::removeProperty(Property* prop) { @@ -142,6 +259,28 @@ void PropertyOwner::removeProperty(Property& prop) { removeProperty(&prop); } + +void PropertyOwner::removePropertySubOwner(openspace::properties::PropertyOwner* owner) { + assert(owner != nullptr); + + // See if we can find the name of the propertyowner to add + std::vector::iterator it + = std::lower_bound(_subOwners.begin(), _subOwners.end(), owner->name(), + [](PropertyOwner* owner, const std::string& str) { + return owner->name() < str; + }); + + // If we found the propertyowner, we can delete it + if (it != _subOwners.end() && (*it)->name() == owner->name()) { + _subOwners.erase(it); + } else + LERROR("PropertyOwner with name '" << owner->name() + << "' not found for removal."); +} + +void PropertyOwner::removePropertySubOwner(openspace::properties::PropertyOwner& owner) { + removePropertySubOwner(&owner); +} void PropertyOwner::setName(std::string name) { diff --git a/src/properties/scalarproperty.cpp b/src/properties/scalarproperty.cpp index 7ee07390a4..6d32284c78 100644 --- a/src/properties/scalarproperty.cpp +++ b/src/properties/scalarproperty.cpp @@ -24,6 +24,8 @@ #include "openspace/properties/scalarproperty.h" +#include + #include using std::numeric_limits; @@ -31,52 +33,137 @@ using std::numeric_limits; namespace openspace { namespace properties { +#define DEFAULT_FROM_LUA_LAMBDA(TYPE, DEFAULT_VALUE) \ + [](lua_State* state, bool& success) -> TYPE { \ + success = (lua_isnumber(state, -1) == 1); \ + if (success) \ + return static_cast(lua_tonumber(state, -1)); \ + else \ + return DEFAULT_VALUE; \ + } + +#define DEFAULT_TO_LUA_LAMBDA(TYPE) \ + [](lua_State* state, TYPE value) -> bool { \ + lua_pushnumber(state, static_cast(value)); \ + return true; \ + } + // char16_t and char32_t are not supported on Visual Studio 2013 and are defined to // be equal to unsigned short and unsigned int which causes a compile error -REGISTER_TEMPLATEPROPERTY_SOURCE(BoolProperty, bool, false); +REGISTER_TEMPLATEPROPERTY_SOURCE(BoolProperty, bool, false, + [](lua_State* state, bool& success) -> bool { + success = (lua_isboolean(state, -1) == 1); + if (success) + return lua_toboolean(state, -1) == 1; + else + return false; + }, + [](lua_State* state, bool value) -> bool { + lua_pushboolean(state, value); + return true; + }, + LUA_TBOOLEAN + ); REGISTER_NUMERICALPROPERTY_SOURCE(CharProperty, char, char(0), - numeric_limits::lowest(), numeric_limits::max(), char(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(Char16Property, char16_t, char16_t(0), -// numeric_limits::lowest(), numeric_limits::max(), char16_t(1)); -//REGISTER_NUMERICALPROPERTY_SOURCE(Char32Property, char32_t, char32_t(0), -// numeric_limits::lowest(), numeric_limits::max(), char32_t(1)); -REGISTER_NUMERICALPROPERTY_SOURCE(WCharProperty, wchar_t, wchar_t(0), - numeric_limits::lowest(), numeric_limits::max(), wchar_t(1)); -REGISTER_NUMERICALPROPERTY_SOURCE(SignedCharProperty, signed char, (signed char)(0), - numeric_limits::lowest(), numeric_limits::max(), - (signed char)0); -REGISTER_NUMERICALPROPERTY_SOURCE(UCharProperty, unsigned char, (unsigned char)0, - numeric_limits::lowest(), numeric_limits::max(), - (unsigned char)1); -REGISTER_NUMERICALPROPERTY_SOURCE(ShortProperty, short, short(0), - numeric_limits::lowest(), numeric_limits::max(), short(1)); -REGISTER_NUMERICALPROPERTY_SOURCE(UShortProperty, unsigned short, (unsigned short)(0), - numeric_limits::lowest(), numeric_limits::max(), - (unsigned short)1); -REGISTER_NUMERICALPROPERTY_SOURCE(IntProperty, int, int(0), - numeric_limits::lowest(), numeric_limits::max(), int(1)); -REGISTER_NUMERICALPROPERTY_SOURCE(UIntProperty, unsigned int, (unsigned int)0, - numeric_limits::lowest(), numeric_limits::max(), - (unsigned int)1); -REGISTER_NUMERICALPROPERTY_SOURCE(LongProperty, long, long(0), - numeric_limits::lowest(), numeric_limits::max(), long(1)); -REGISTER_NUMERICALPROPERTY_SOURCE(ULongProperty, unsigned long, (unsigned long)0, - numeric_limits::lowest(), numeric_limits::max(), - (unsigned long)1); -REGISTER_NUMERICALPROPERTY_SOURCE(LongLongProperty, long long, (long long)0, - numeric_limits::lowest(), numeric_limits::max(), (long long)1); -REGISTER_NUMERICALPROPERTY_SOURCE(ULongLongProperty, unsigned long long, - (unsigned long long)1, numeric_limits::lowest(), - numeric_limits::max(), (unsigned long long)1); -REGISTER_NUMERICALPROPERTY_SOURCE(FloatProperty, float, 0.f, - numeric_limits::lowest(), numeric_limits::max(), 0.01f); -REGISTER_NUMERICALPROPERTY_SOURCE(DoubleProperty, double, 0.0, - numeric_limits::lowest(), numeric_limits::max(), 0.01); -REGISTER_NUMERICALPROPERTY_SOURCE(LongDoubleProperty, long double, (long double)0, - numeric_limits::lowest(), numeric_limits::max(), - (long double)0.01f); + numeric_limits::lowest(), + numeric_limits::max(), char(1), + DEFAULT_FROM_LUA_LAMBDA(char, char(0)), + DEFAULT_TO_LUA_LAMBDA(char), LUA_TNUMBER); -} // namespace properties +// REGISTER_NUMERICALPROPERTY_SOURCE(Char16Property, char16_t, char16_t(0), +// numeric_limits::lowest(), numeric_limits::max(), char16_t(1)); + +// REGISTER_NUMERICALPROPERTY_SOURCE(Char32Property, char32_t, char32_t(0), +// numeric_limits::lowest(), numeric_limits::max(), char32_t(1)); + +REGISTER_NUMERICALPROPERTY_SOURCE(WCharProperty, wchar_t, wchar_t(0), + numeric_limits::lowest(), + numeric_limits::max(), wchar_t(1), + DEFAULT_FROM_LUA_LAMBDA(wchar_t, wchar_t(0)), + DEFAULT_TO_LUA_LAMBDA(wchar_t), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(SignedCharProperty, signed char, (signed char)(0), + numeric_limits::lowest(), + numeric_limits::max(), (signed char)0, + DEFAULT_FROM_LUA_LAMBDA(signed char, (signed char)(0)), + DEFAULT_TO_LUA_LAMBDA(signed char), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(UCharProperty, unsigned char, (unsigned char)0, + numeric_limits::lowest(), + numeric_limits::max(), (unsigned char)1, + DEFAULT_FROM_LUA_LAMBDA(unsigned char, + (unsigned char)(0)), + DEFAULT_TO_LUA_LAMBDA(unsigned char), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(ShortProperty, short, short(0), + numeric_limits::lowest(), + numeric_limits::max(), short(1), + DEFAULT_FROM_LUA_LAMBDA(short, short(0)), + DEFAULT_TO_LUA_LAMBDA(short), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE( + UShortProperty, unsigned short, (unsigned short)(0), + numeric_limits::lowest(), numeric_limits::max(), + (unsigned short)1, DEFAULT_FROM_LUA_LAMBDA(unsigned short, (unsigned short)(0)), + DEFAULT_TO_LUA_LAMBDA(unsigned short), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(IntProperty, int, int(0), numeric_limits::lowest(), + numeric_limits::max(), int(1), + DEFAULT_FROM_LUA_LAMBDA(int, int(0)), + DEFAULT_TO_LUA_LAMBDA(int), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(UIntProperty, unsigned int, (unsigned int)0, + numeric_limits::lowest(), + numeric_limits::max(), (unsigned int)1, + DEFAULT_FROM_LUA_LAMBDA(unsigned int, + (unsigned int)(0)), + DEFAULT_TO_LUA_LAMBDA(unsigned int), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(LongProperty, long, long(0), + numeric_limits::lowest(), + numeric_limits::max(), long(1), + DEFAULT_FROM_LUA_LAMBDA(long, long(0)), + DEFAULT_TO_LUA_LAMBDA(long), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(ULongProperty, unsigned long, (unsigned long)0, + numeric_limits::lowest(), + numeric_limits::max(), (unsigned long)1, + DEFAULT_FROM_LUA_LAMBDA(unsigned long, + (unsigned long)(0)), + DEFAULT_TO_LUA_LAMBDA(unsigned long), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(LongLongProperty, long long, (long long)0, + numeric_limits::lowest(), + numeric_limits::max(), (long long)1, + DEFAULT_FROM_LUA_LAMBDA(long long, (long long)(0)), + DEFAULT_TO_LUA_LAMBDA(long long), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE( + ULongLongProperty, unsigned long long, (unsigned long long)1, + numeric_limits::lowest(), + numeric_limits::max(), (unsigned long long)1, + DEFAULT_FROM_LUA_LAMBDA(unsigned long long, (unsigned long long)(0)), + DEFAULT_TO_LUA_LAMBDA(unsigned long long), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(FloatProperty, float, 0.f, + numeric_limits::lowest(), + numeric_limits::max(), 0.01f, + DEFAULT_FROM_LUA_LAMBDA(float, float(0)), + DEFAULT_TO_LUA_LAMBDA(float), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(DoubleProperty, double, 0.0, + numeric_limits::lowest(), + numeric_limits::max(), 0.01, + DEFAULT_FROM_LUA_LAMBDA(double, double(0)), + DEFAULT_TO_LUA_LAMBDA(double), LUA_TNUMBER); + +REGISTER_NUMERICALPROPERTY_SOURCE(LongDoubleProperty, long double, (long double)0, + numeric_limits::lowest(), + numeric_limits::max(), (long double)0.01f, + DEFAULT_FROM_LUA_LAMBDA(long double, (long double)(0)), + DEFAULT_TO_LUA_LAMBDA(long double), LUA_TNUMBER); + +} // namespace properties } // namespace openspace diff --git a/src/properties/stringproperty.cpp b/src/properties/stringproperty.cpp index a60115cd29..2b5d51d5b6 100644 --- a/src/properties/stringproperty.cpp +++ b/src/properties/stringproperty.cpp @@ -24,38 +24,25 @@ #include +#include + namespace openspace { namespace properties { -StringProperty::StringProperty(std::string identifier, std::string guiName) - : StringProperty( - std::move(identifier), std::move(guiName), - PropertyDelegate>::defaultValue()) -{ -} - -StringProperty::StringProperty(std::string identifier, std::string guiName, - std::string value) - : TemplateProperty(std::move(identifier), std::move(guiName), std::move(value)) -{} - -template <> -std::string PropertyDelegate>::className() { - return "StringProperty"; -} - -template <> -template <> -std::string PropertyDelegate>::defaultValue() { - return ""; -} - - -//REGISTER_TEMPLATEPROPERTY_SOURCE(StringProperty, std::string, ""); -// -//std::string openspace::properties::StringProperty::className() const { -// return "StringProperty"; -//} +REGISTER_TEMPLATEPROPERTY_SOURCE(StringProperty, std::string, "", +[](lua_State* state, bool& success) -> std::string { + success = lua_isstring(state, -1) == 1; + if (success) + return lua_tostring(state, -1); + else + return ""; + }, +[](lua_State* state, std::string value) -> bool { + lua_pushstring(state, value.c_str()); + return true; + }, +LUA_TSTRING +); } // namespace properties } // namespace openspace diff --git a/src/properties/vectorproperty.cpp b/src/properties/vectorproperty.cpp index 99b1dddead..f05299cb37 100644 --- a/src/properties/vectorproperty.cpp +++ b/src/properties/vectorproperty.cpp @@ -24,6 +24,10 @@ #include "openspace/properties/vectorproperty.h" +#include + +#include + #include using std::numeric_limits; @@ -31,46 +35,150 @@ using std::numeric_limits; namespace openspace { namespace properties { -REGISTER_TEMPLATEPROPERTY_SOURCE(BVec2Property, glm::bvec2, glm::bvec2(false)); -REGISTER_TEMPLATEPROPERTY_SOURCE(BVec3Property, glm::bvec3, glm::bvec3(false)); -REGISTER_TEMPLATEPROPERTY_SOURCE(BVec4Property, glm::bvec4, glm::bvec4(false)); +#define DEFAULT_FROM_LUA_LAMBDA(__TYPE__, __CONVFUNC__, __TESTFUNC__) \ + [](lua_State * state, bool& success) -> __TYPE__ { \ + __TYPE__ result; \ + int number = 1; \ + for (__TYPE__::size_type i = 0; i < result.length(); ++i) { \ + lua_getfield(state, -1, std::to_string(number).c_str()); \ + if (__TESTFUNC__(state, -1) != 1) { \ + success = false; \ + return __TYPE__(0); \ + } else { \ + result[i] = static_cast<__TYPE__::value_type>(__CONVFUNC__(state, -1)); \ + lua_pop(state, 1); \ + ++number; \ + } \ + } \ + success = true; \ + return result; \ + } + +#define DEFAULT_TO_LUA_LAMBDA(__TYPE__) \ + [](lua_State * state, __TYPE__ value) -> bool { \ + lua_newtable(state); \ + int number = 1; \ + for (__TYPE__::size_type i = 0; i < value.length(); ++i) { \ + lua_pushnumber(state, static_cast(value[i])); \ + lua_setfield(state, -2, std::to_string(number).c_str()); \ + ++number; \ + } \ + return true; \ + } + + +// Forcing value from int to bool is acceptable here (line 48) +#ifdef WIN32 +#pragma warning(disable : 4800) +#endif + + +REGISTER_TEMPLATEPROPERTY_SOURCE(BVec2Property, glm::bvec2, glm::bvec2(false), + DEFAULT_FROM_LUA_LAMBDA(glm::bvec2, lua_toboolean, + lua_isboolean), + DEFAULT_TO_LUA_LAMBDA(glm::bvec2), LUA_TTABLE); + +REGISTER_TEMPLATEPROPERTY_SOURCE(BVec3Property, glm::bvec3, glm::bvec3(false), + DEFAULT_FROM_LUA_LAMBDA(glm::bvec3, lua_toboolean, + lua_isboolean), + DEFAULT_TO_LUA_LAMBDA(glm::bvec3), LUA_TTABLE); + +REGISTER_TEMPLATEPROPERTY_SOURCE(BVec4Property, glm::bvec4, glm::bvec4(false), + DEFAULT_FROM_LUA_LAMBDA(glm::bvec4, lua_toboolean, + lua_isboolean), + DEFAULT_TO_LUA_LAMBDA(glm::bvec4), LUA_TTABLE); + +#ifdef WIN32 +#pragma warning(default : 4800) +#endif + + +REGISTER_NUMERICALPROPERTY_SOURCE( + Vec2Property, glm::vec2, glm::vec2(0), glm::vec2(numeric_limits::lowest()), + glm::vec2(numeric_limits::max()), glm::vec2(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::vec2, lua_tonumber, lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::vec2), LUA_TTABLE); + +REGISTER_NUMERICALPROPERTY_SOURCE( + Vec3Property, glm::vec3, glm::vec3(0), glm::vec3(numeric_limits::lowest()), + glm::vec3(numeric_limits::max()), glm::vec3(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::vec3, lua_tonumber, lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::vec3), LUA_TTABLE); + +REGISTER_NUMERICALPROPERTY_SOURCE( + Vec4Property, glm::vec4, glm::vec4(0), glm::vec4(numeric_limits::lowest()), + glm::vec4(numeric_limits::max()), glm::vec4(0.01f), + DEFAULT_FROM_LUA_LAMBDA(glm::vec4, lua_tonumber, lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::vec4), LUA_TTABLE); -REGISTER_NUMERICALPROPERTY_SOURCE(Vec2Property, glm::vec2, glm::vec2(0), - glm::vec2(numeric_limits::lowest()), glm::vec2(numeric_limits::max()), - glm::vec2(0.01f)); -REGISTER_NUMERICALPROPERTY_SOURCE(Vec3Property, glm::vec3, glm::vec3(0), - glm::vec3(numeric_limits::lowest()), glm::vec3(numeric_limits::max()), - glm::vec3(0.01f)); -REGISTER_NUMERICALPROPERTY_SOURCE(Vec4Property, glm::vec4, glm::vec4(0), - glm::vec4(numeric_limits::lowest()), glm::vec4(numeric_limits::max()), - glm::vec4(0.01f)); REGISTER_NUMERICALPROPERTY_SOURCE(DVec2Property, glm::dvec2, glm::dvec2(0), - glm::dvec2(numeric_limits::lowest()), - glm::dvec2(numeric_limits::max()), glm::dvec2(0.01)); + glm::dvec2(numeric_limits::lowest()), + glm::dvec2(numeric_limits::max()), + glm::dvec2(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dvec2, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::dvec2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DVec3Property, glm::dvec3, glm::dvec3(0), - glm::dvec3(numeric_limits::lowest()), - glm::dvec3(numeric_limits::max()), glm::dvec3(0.01)); + glm::dvec3(numeric_limits::lowest()), + glm::dvec3(numeric_limits::max()), + glm::dvec3(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dvec3, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::dvec3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(DVec4Property, glm::dvec4, glm::dvec4(0), - glm::dvec4(numeric_limits::lowest()), - glm::dvec4(numeric_limits::max()), glm::dvec4(0.01)); + glm::dvec4(numeric_limits::lowest()), + glm::dvec4(numeric_limits::max()), + glm::dvec4(0.01), + DEFAULT_FROM_LUA_LAMBDA(glm::dvec4, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::dvec4), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(IVec2Property, glm::ivec2, glm::ivec2(0), - glm::ivec2(numeric_limits::lowest()), glm::ivec2(numeric_limits::max()), - glm::ivec2(1)); + glm::ivec2(numeric_limits::lowest()), + glm::ivec2(numeric_limits::max()), glm::ivec2(1), + DEFAULT_FROM_LUA_LAMBDA(glm::ivec2, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::ivec2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(IVec3Property, glm::ivec3, glm::ivec3(0), - glm::ivec3(numeric_limits::lowest()), glm::ivec3(numeric_limits::max()), - glm::ivec3(1)); + glm::ivec3(numeric_limits::lowest()), + glm::ivec3(numeric_limits::max()), glm::ivec3(1), + DEFAULT_FROM_LUA_LAMBDA(glm::ivec3, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::ivec3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(IVec4Property, glm::ivec4, glm::ivec4(0), - glm::ivec4(numeric_limits::lowest()), glm::ivec4(numeric_limits::max()), - glm::ivec4(1)); + glm::ivec4(numeric_limits::lowest()), + glm::ivec4(numeric_limits::max()), glm::ivec4(1), + DEFAULT_FROM_LUA_LAMBDA(glm::ivec4, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::ivec4), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(UVec2Property, glm::uvec2, glm::uvec2(0), - glm::uvec2(numeric_limits::lowest()), - glm::uvec2(numeric_limits::max()), glm::uvec2(1)); + glm::uvec2(numeric_limits::lowest()), + glm::uvec2(numeric_limits::max()), + glm::uvec2(1), + DEFAULT_FROM_LUA_LAMBDA(glm::uvec2, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::uvec2), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(UVec3Property, glm::uvec3, glm::uvec3(0), - glm::uvec3(numeric_limits::lowest()), - glm::uvec3(numeric_limits::max()), glm::uvec3(1)); + glm::uvec3(numeric_limits::lowest()), + glm::uvec3(numeric_limits::max()), + glm::uvec3(1), + DEFAULT_FROM_LUA_LAMBDA(glm::uvec3, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::uvec3), LUA_TTABLE); + REGISTER_NUMERICALPROPERTY_SOURCE(UVec4Property, glm::uvec4, glm::uvec4(0), - glm::uvec4(numeric_limits::lowest()), - glm::uvec4(numeric_limits::max()), glm::uvec4(1)); + glm::uvec4(numeric_limits::lowest()), + glm::uvec4(numeric_limits::max()), + glm::uvec4(1), + DEFAULT_FROM_LUA_LAMBDA(glm::uvec4, lua_tonumber, + lua_isnumber), + DEFAULT_TO_LUA_LAMBDA(glm::uvec4), LUA_TTABLE); } // namespace properties } // namespace openspace diff --git a/src/query/query.cpp b/src/query/query.cpp index 5e814b0f9a..404758a59f 100644 --- a/src/query/query.cpp +++ b/src/query/query.cpp @@ -25,22 +25,47 @@ #include #include +#include namespace openspace { namespace { -const std::string _loggerCat = "Query"; + const std::string _loggerCat = "Query"; } -SceneGraph* getSceneGraph() +SceneGraph* sceneGraph() { return OsEng.renderEngine().sceneGraph(); } -SceneGraphNode* getSceneGraphNode(const std::string& name) +SceneGraphNode* sceneGraphNode(const std::string& name) { - SceneGraph* sceneGraph = getSceneGraph(); - return sceneGraph->sceneGraphNode(name); + const SceneGraph* graph = sceneGraph(); + return graph->sceneGraphNode(name); +} + +properties::Property* property(const std::string& uri) +{ + // The URI consists of the following form at this stage: + // .{.}^(0..n) + + const size_t nodeNameSeparator = uri.find(properties::PropertyOwner::URISeparator); + if (nodeNameSeparator == std::string::npos) { + LERROR("Malformed URI '" << uri << "': At least one '" << nodeNameSeparator + << "' separator must be present."); + return nullptr; + } + const std::string nodeName = uri.substr(0, nodeNameSeparator); + const std::string remainingUri = uri.substr(nodeNameSeparator + 1); + + SceneGraphNode* node = sceneGraphNode(nodeName); + if (!node) { + LERROR("Node '" << nodeName << "' did not exist"); + return nullptr; + } + + properties::Property* property = node->property(remainingUri); + return property; } } // namespace diff --git a/src/rendering/planets/planetgeometry.cpp b/src/rendering/planets/planetgeometry.cpp index b9cef75f05..547984a8fe 100644 --- a/src/rendering/planets/planetgeometry.cpp +++ b/src/rendering/planets/planetgeometry.cpp @@ -36,17 +36,14 @@ namespace planetgeometry { PlanetGeometry* PlanetGeometry::createFromDictionary(const ghoul::Dictionary& dictionary) { - std::string name; - dictionary.getValue(constants::scenegraphnode::keyName, name); - - if (!dictionary.hasValue(constants::planetgeometry::keyType)) { - LERROR("PlanetGeometry for '" << name << "' did not contain a '" - << constants::planetgeometry::keyType << "' key"); + std::string geometryType; + const bool success = dictionary.getValueSafe( + constants::planetgeometry::keyType, geometryType); + if (!success) { + LERROR("PlanetGeometry did not contain a correct value of the key '" + << constants::planetgeometry::keyType << "'"); return nullptr; - } - std::string geometryType; - dictionary.getValue(constants::planetgeometry::keyType, geometryType); - + } ghoul::TemplateFactory* factory = FactoryManager::ref().factory(); @@ -62,6 +59,7 @@ PlanetGeometry* PlanetGeometry::createFromDictionary(const ghoul::Dictionary& di PlanetGeometry::PlanetGeometry() : _parent(nullptr) { + setName("PlanetGeometry"); } PlanetGeometry::~PlanetGeometry() diff --git a/src/rendering/planets/renderableplanet.cpp b/src/rendering/planets/renderableplanet.cpp index b1876e8216..3775aa1c81 100644 --- a/src/rendering/planets/renderableplanet.cpp +++ b/src/rendering/planets/renderableplanet.cpp @@ -47,31 +47,34 @@ RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) , _texture(nullptr) , _geometry(nullptr) { + std::string name; + bool success = dictionary.getValue(constants::scenegraphnode::keyName, name); + assert(success); + std::string path; - dictionary.getValue(constants::scenegraph::keyPathModule, path); + success = dictionary.getValue(constants::scenegraph::keyPathModule, path); + assert(success); - if (dictionary.hasKey(constants::renderableplanet::keyGeometry)) { - ghoul::Dictionary geometryDictionary; - dictionary.getValue(constants::renderableplanet::keyGeometry, geometryDictionary); + ghoul::Dictionary geometryDictionary; + success = dictionary.getValueSafe( + constants::renderableplanet::keyGeometry, geometryDictionary); + if (success) { + geometryDictionary.setValue(constants::scenegraphnode::keyName, name); geometryDictionary.setValue(constants::scenegraph::keyPathModule, path); - geometryDictionary.setValue(constants::scenegraphnode::keyName, name()); - _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geometryDictionary); - } + } // TODO: textures need to be replaced by a good system similar to the geometry as soon // as the requirements are fixed (ab) std::string texturePath = ""; - if (dictionary.hasKey("Textures.Color")) { - dictionary.getValue("Textures.Color", texturePath); + success = dictionary.getValueSafe("Textures.Color", texturePath); + if (success) _colorTexturePath = path + "/" + texturePath; - } - for (properties::Property* p : _geometry->properties()) - addProperty(p); + addPropertySubOwner(_geometry); - addProperty(_colorTexturePath); + addProperty(_colorTexturePath); _colorTexturePath.onChange(std::bind(&RenderablePlanet::loadTexture, this)); } @@ -107,10 +110,10 @@ bool RenderablePlanet::deinitialize() void RenderablePlanet::render(const Camera* camera, const psc& thisPosition) { - // TODO replace with more robust assert - // check so that the shader is set - assert(_programObject); - assert(_texture); + if (!_programObject) + return; + if (!_texture) + return; // activate shader _programObject->activate(); diff --git a/src/rendering/planets/simplespheregeometry.cpp b/src/rendering/planets/simplespheregeometry.cpp index 5c544d49fd..e016f37f4c 100644 --- a/src/rendering/planets/simplespheregeometry.cpp +++ b/src/rendering/planets/simplespheregeometry.cpp @@ -47,38 +47,37 @@ SimpleSphereGeometry::SimpleSphereGeometry(const ghoul::Dictionary& dictionary) , _segments("segments", "Segments", 20, 1, 1000) , _planet(nullptr) { - if (!dictionary.hasValue(constants::simplespheregeometry::keyRadius)) { - std::string name; - dictionary.getValue(constants::scenegraphnode::keyName, name); - LERROR("SimpleSphereGeometry of '" << name << "' did not provide a key '" - << constants::simplespheregeometry::keyRadius - << "'"); - } - else { - glm::vec2 radius; - dictionary.getValue(constants::simplespheregeometry::keyRadius, radius); - _radius = radius; - } + using constants::scenegraphnode::keyName; + using constants::simplespheregeometry::keyRadius; + using constants::simplespheregeometry::keySegments; - if (!dictionary.hasValue(constants::simplespheregeometry::keySegments)) { - std::string name; - dictionary.getValue(constants::scenegraphnode::keyName, name); + // The name is passed down from the SceneGraphNode + std::string name; + bool success = dictionary.getValue(keyName, name); + assert(success); + + glm::vec2 radius; + success = dictionary.getValueSafe(keyRadius, radius); + if (!success) { LERROR("SimpleSphereGeometry of '" << name << "' did not provide a key '" - << constants::simplespheregeometry::keySegments - << "'"); - } - else { - float segments; - dictionary.getValue(constants::simplespheregeometry::keySegments, segments); - _segments = static_cast(segments); - } + << keyRadius << "'"); + } + else + _radius = radius; + + int segments; + success = dictionary.getValueSafe(keySegments, segments); + if (!success) { + LERROR("SimpleSphereGeometry of '" << name << "' did not provide a key '" + << keySegments << "'"); + } + else + _segments = segments; addProperty(_radius); _radius.onChange(std::bind(&SimpleSphereGeometry::createSphere, this)); addProperty(_segments); _segments.onChange(std::bind(&SimpleSphereGeometry::createSphere, this)); - - //createSphere(); } SimpleSphereGeometry::~SimpleSphereGeometry() diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 9a432b02d7..7c497be81c 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -27,6 +27,8 @@ #include #include +#include + namespace { const std::string _loggerCat = "Renderable"; } @@ -35,16 +37,19 @@ namespace openspace { Renderable* Renderable::createFromDictionary(const ghoul::Dictionary& dictionary) { + // The name is passed down from the SceneGraphNode std::string name; - dictionary.getValue(constants::scenegraphnode::keyName, name); + bool success = dictionary.getValue(constants::scenegraphnode::keyName, name); + assert(success); - if (!dictionary.hasValue(constants::renderable::keyType)) { + std::string renderableType; + success = dictionary.getValueSafe(constants::renderable::keyType, renderableType); + if (!success) { LERROR("Renderable '" << name << "' did not have key '" << constants::renderable::keyType << "'"); return nullptr; - } - std::string renderableType; - dictionary.getValue(constants::renderable::keyType, renderableType); + } + ghoul::TemplateFactory* factory = FactoryManager::ref().factory(); Renderable* result = factory->create(renderableType, dictionary); @@ -53,16 +58,20 @@ Renderable* Renderable::createFromDictionary(const ghoul::Dictionary& dictionary return nullptr; } - result->setName(name); - return result; } Renderable::Renderable(const ghoul::Dictionary& dictionary) + : _enabled("enabled", "Is Enabled", true) { - std::string name; - dictionary.getValue(constants::scenegraphnode::keyName, name); - setName(name); + setName("renderable"); + + // get path if available + const bool success = dictionary.getValueSafe(constants::scenegraph::keyPathModule, _relativePath); + if (success) + _relativePath += ghoul::filesystem::FileSystem::PathSeparator; + + addProperty(_enabled); } Renderable::~Renderable() @@ -83,4 +92,22 @@ void Renderable::update() { } -} // namespace openspace \ No newline at end of file +std::string Renderable::findPath(const std::string& path) { + std::string tmp = absPath(path); + if(FileSys.fileExists(tmp)) + return tmp; + + tmp = absPath(_relativePath + path); + if(FileSys.fileExists(tmp)) + return tmp; + + LERROR("Could not find file '" << path << "'"); + + return ""; +} + +bool Renderable::isVisible() const { + return _enabled; +} + +} // namespace openspace diff --git a/src/rendering/renderablefieldlines.cpp b/src/rendering/renderablefieldlines.cpp new file mode 100644 index 0000000000..1817400413 --- /dev/null +++ b/src/rendering/renderablefieldlines.cpp @@ -0,0 +1,342 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include +#include +#include + +#include + +namespace { + const std::string _loggerCat = "RenderableFieldlines"; + + const std::string keyFieldlines = "Fieldlines"; + const std::string keyFilename = "File"; + const std::string keyHints = "Hints"; + const std::string keyShaders = "Shaders"; + const std::string keyVertexShader = "VertexShader"; + const std::string keyFragmentShader = "FragmentShader"; +} + +namespace openspace { + +RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _VAO(0) + , _programUpdateOnSave(false) + , _update(false) +{ + std::string name; + bool success = dictionary.getValue(constants::scenegraphnode::keyName, name); + assert(success); + + ghoul::Dictionary fieldlines; + success = dictionary.getValueSafe(keyFieldlines, fieldlines); + if (!success) { + LERROR("RenderableFieldlines '" << name << "' did not contain a '" << + keyFieldlines << "' key"); + return; + } + for (const std::string& key : fieldlines.keys()) { + ghoul::Dictionary fieldline; + success = fieldlines.getValueSafe(key, fieldline); + + if (!success) { + LERROR("Key '" << key << "' in '" << keyFieldlines << + "' of the RenderableFieldlines '" << name << + "' does not have a table as value"); + continue; + } + + std::string fileName; + fieldline.getValueSafe(keyFilename, fileName); + fileName = findPath(fileName); + if (fileName.empty()) + LERROR("File not found!"); + else { + ghoul::Dictionary hintsDictionary; + fieldline.getValueSafe(keyHints, hintsDictionary); + + _filenames.push_back(fileName); + _hintsDictionaries.push_back(hintsDictionary); + } + } + + ghoul::Dictionary shaderDictionary; + success = dictionary.getValueSafe(keyShaders, shaderDictionary); + if (!success) { + LERROR("RenderableFieldlines '" << name << "' does not contain a '" << + keyShaders << "' table"); + return; + } + + std::string vshaderpath; + success = shaderDictionary.getValueSafe(keyVertexShader, vshaderpath); + if (!success) { + LERROR("RenderableFieldlines '" << name << "' does not have a '" << + keyVertexShader << "'"); + return; + } + vshaderpath = findPath(vshaderpath); + + std::string fshaderpath; + success = shaderDictionary.getValueSafe(keyFragmentShader, fshaderpath); + if (!success) { + LERROR("RenderableFieldlines '" << name << "' does not have a '" << + keyFragmentShader << "'"); + return; + } + fshaderpath = findPath(fshaderpath); + + _vertexSourceFile = new ghoul::filesystem::File(vshaderpath, false); + _fragmentSourceFile = new ghoul::filesystem::File(fshaderpath, false); + + + ShaderCreator sc = OsEng.shaderBuilder(); + _fieldlinesProgram = sc.buildShader("FieldlinesProgram", vshaderpath, fshaderpath); + + dictionary.getValueSafe("UpdateOnSave", _programUpdateOnSave); + + setBoundingSphere(PowerScaledScalar::CreatePSS(5)); // FIXME a non-magic number perhaps +} + +RenderableFieldlines::~RenderableFieldlines() { +} + +bool RenderableFieldlines::initialize() { + assert(_filenames.size() != 0); + assert(_hintsDictionaries.size() != 0); + + int prevEnd = 0; + std::vector vertexData, seedPointsData; + std::vector > fieldlinesData; + glm::vec4 seedPointsColor = glm::vec4(1.0, 0.5, 0.0, 1.0); + + for (int i = 0; i < _filenames.size(); ++i) { + fieldlinesData = getFieldlinesData(_filenames[i], _hintsDictionaries[i]); + + for (int j = 0; j < fieldlinesData.size(); ++j) { + _lineStart.push_back(prevEnd); + _lineCount.push_back(fieldlinesData[j].size()); + prevEnd = prevEnd + fieldlinesData[j].size(); + vertexData.insert( vertexData.end(), fieldlinesData[j].begin(), fieldlinesData[j].end()); + } + // Give seedpoints a color for visualizing as GL_POINTS + for (glm::vec3 seedPoint : _seedPoints) { + seedPointsData.push_back(LinePoint(seedPoint, seedPointsColor)); + } + } + LDEBUG("Number of vertices : " << vertexData.size()); + + // ------ FIELDLINES ----------------- + GLuint vertexPositionBuffer; + glGenVertexArrays(1, &_VAO); // generate array + glBindVertexArray(_VAO); // bind array + glGenBuffers(1, &vertexPositionBuffer); // generate buffer + glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer + glBufferData(GL_ARRAY_BUFFER, vertexData.size()*sizeof(LinePoint), &vertexData.front(), GL_STATIC_DRAW); + + // Vertex positions + GLuint vertexLocation = 0; + glEnableVertexAttribArray(vertexLocation); + glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(LinePoint), reinterpret_cast(0)); + + // Texture coordinates + GLuint texcoordLocation = 1; + glEnableVertexAttribArray(texcoordLocation); + glVertexAttribPointer(texcoordLocation, 4, GL_FLOAT, GL_FALSE, sizeof(LinePoint), (void*)(sizeof(glm::vec3))); + + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer + glBindVertexArray(0); //unbind array + + // ------ SEEDPOINTS ----------------- + GLuint seedpointPositionBuffer; + glGenVertexArrays(1, &_seedpointVAO); // generate array + glBindVertexArray(_seedpointVAO); // bind array + glGenBuffers(1, &seedpointPositionBuffer); // generate buffer + glBindBuffer(GL_ARRAY_BUFFER, seedpointPositionBuffer); // bind buffer + glBufferData(GL_ARRAY_BUFFER, seedPointsData.size()*sizeof(LinePoint), &seedPointsData.front(), GL_STATIC_DRAW); + + // Vertex positions + glEnableVertexAttribArray(vertexLocation); + glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, sizeof(LinePoint), reinterpret_cast(0)); + + // Texture coordinates + glEnableVertexAttribArray(texcoordLocation); + glVertexAttribPointer(texcoordLocation, 4, GL_FLOAT, GL_FALSE, sizeof(LinePoint), (void*)(3*sizeof(float))); + + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer + glBindVertexArray(0); //unbind array + + glPointSize(5); // size of seedpoints + + // ------ SETUP SHADERS ----------------- + auto privateCallback = [this](const ghoul::filesystem::File& file) { + _update = true; + }; + if(_programUpdateOnSave) { + _vertexSourceFile->setCallback(privateCallback); + _fragmentSourceFile->setCallback(privateCallback); + } + + _fieldlinesProgram->compileShaderObjects(); + _fieldlinesProgram->linkProgramObject(); + + return true; +} + +bool RenderableFieldlines::deinitialize() { + return true; +} + +void RenderableFieldlines::render(const Camera* camera, const psc& thisPosition) { + if(_update) { + _update = false; + safeShaderCompilation(); + } + + glm::mat4 transform = camera->viewProjectionMatrix(); + glm::mat4 camTransform = camera->viewRotationMatrix(); + psc relative = thisPosition-camera->position(); + + transform = transform*camTransform; + transform = glm::mat4(1.0); + transform = glm::scale(transform, glm::vec3(0.01)); + + psc currentPosition = thisPosition; + psc campos = camera->position(); + glm::mat4 camrot = camera->viewRotationMatrix(); + PowerScaledScalar scaling = camera->scaling(); + + // Activate shader + _fieldlinesProgram->activate(); + + _fieldlinesProgram->setUniform("modelViewProjection", camera->viewProjectionMatrix()); + _fieldlinesProgram->setUniform("modelTransform", transform); + _fieldlinesProgram->setUniform("campos", campos.vec4()); + _fieldlinesProgram->setUniform("objpos", currentPosition.vec4()); + _fieldlinesProgram->setUniform("camrot", camrot); + _fieldlinesProgram->setUniform("scaling", scaling.vec2()); + + // ------ FIELDLINES ----------------- + glBindVertexArray(_VAO); + glMultiDrawArrays(GL_LINE_STRIP, &_lineStart[0], &_lineCount[0], _lineStart.size()); + +// // ------ SEEDPOINTS ----------------- +// glBindVertexArray(_seedpointVAO); +// glMultiDrawArrays(GL_POINTS, &_lineStart[0], &_lineCount[0], _seedPoints.size()); + glBindVertexArray(0); + + // Deactivate shader + _fieldlinesProgram->deactivate(); +} + +void RenderableFieldlines::update() { +} + +void RenderableFieldlines::safeShaderCompilation() { + _fieldlinesProgram->rebuildFromFile(); + _fieldlinesProgram->compileShaderObjects(); + _fieldlinesProgram->linkProgramObject(); +} + +std::vector > RenderableFieldlines::getFieldlinesData(std::string filename, ghoul::Dictionary hintsDictionary) { + std::string modelString; + float stepSize = 0.5; // default if no stepsize is specified in hints + std::string xVariable, yVariable, zVariable; + KameleonWrapper::Model model; + std::vector > fieldlinesData; + + bool classification = false, lorentz = false; + glm::vec4 fieldlineColor = glm::vec4(1.0, 1.0, 1.0, 1.0); // default color if no color or classification is specified + + if (hintsDictionary.hasKey("Model") && hintsDictionary.getValue("Model", modelString)) { + // ------ MODEL ----------------- + if (modelString == "BATSRUS") { + model = KameleonWrapper::Model::BATSRUS; + } else if (modelString == "ENLIL") { + LWARNING("ENLIL model not supported for fieldlines"); + return fieldlinesData; + } else { + LWARNING("Hints does not specify a valid 'Model'"); + return fieldlinesData; + } + + // ------ VARIBLES / LORENTZ ----------------- + if (hintsDictionary.hasKey("Variables")) { + bool xVar, yVar, zVar; + xVar = hintsDictionary.getValue("Variables.1", xVariable); + if (xVar && xVariable == "Lorentz") { + lorentz = true; + } else { + + yVar = hintsDictionary.getValue("Variables.2", yVariable); + zVar = hintsDictionary.getValue("Variables.3", zVariable); + + if (!xVar || !yVar || !zVar) { + LWARNING("Error reading variables! Must be 3 and must exist in CDF data"); + return fieldlinesData; + } + } + } else { + LWARNING("Hints does not specify valid 'Variables'"); + return fieldlinesData; + } + + // ------ STEPSIZE ----------------- + if (!hintsDictionary.hasKey("Stepsize") || !hintsDictionary.getValue("Stepsize", stepSize)) { + LDEBUG("No stepsize set for fieldlines. Setting to default value (" << stepSize << ")"); + } + + // ------ SEEDPOINTS --------------- + ghoul::Dictionary seedpointsDictionary; + _seedPoints.clear(); + if (hintsDictionary.hasKey("Seedpoints") && hintsDictionary.getValue("Seedpoints", seedpointsDictionary)) { + glm::vec3 seedPos; + for (auto index : seedpointsDictionary.keys()) { + hintsDictionary.getValue("Seedpoints."+index, seedPos); + _seedPoints.push_back(seedPos); + } + } + + // ------ CLASSIFICATION & COLOR ----------- + hintsDictionary.getValue("Color", fieldlineColor); + hintsDictionary.getValue("Classification", classification); + } + + KameleonWrapper kw(filename, model); + if (lorentz) { + fieldlinesData = kw.getLorentzTrajectories(_seedPoints, fieldlineColor, stepSize); + } else { + if (classification) + fieldlinesData = kw.getClassifiedFieldLines(xVariable, yVariable, zVariable, _seedPoints, stepSize); + else + fieldlinesData = kw.getFieldLines(xVariable, yVariable, zVariable, _seedPoints, stepSize, fieldlineColor); + } + + return fieldlinesData; +} + +} // namespace openspace diff --git a/src/rendering/renderablevolume.cpp b/src/rendering/renderablevolume.cpp index c96b8ca7ae..7ecaf4274f 100644 --- a/src/rendering/renderablevolume.cpp +++ b/src/rendering/renderablevolume.cpp @@ -24,17 +24,16 @@ // open space includes #include - -#include -#include - #include #include #include -#include +// ghoul includes +#include +#include #include +#include #include #include #include @@ -73,92 +72,178 @@ namespace { namespace openspace { -RenderableVolume::RenderableVolume(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) -{ - // get path if available - _relativePath = ""; - if(dictionary.hasKey(constants::scenegraph::keyPathModule)) { - dictionary.getValue(constants::scenegraph::keyPathModule, _relativePath); - _relativePath += "/"; - } +RenderableVolume::RenderableVolume(const ghoul::Dictionary& dictionary) : Renderable(dictionary) { } RenderableVolume::~RenderableVolume() { } -std::string RenderableVolume::findPath(const std::string& path) { - std::string tmp = absPath(path); - if(FileSys.fileExists(tmp)) - return tmp; - - tmp = absPath(_relativePath + path); - if(FileSys.fileExists(tmp)) - return tmp; - - LERROR("Could not find file '" << path << "'"); - - return ""; +ghoul::opengl::Texture* RenderableVolume::loadVolume( + const std::string& filepath, + const ghoul::Dictionary& hintsDictionary) { + + + if( ! FileSys.fileExists(filepath)) { + LWARNING("Could not load volume, could not find '" << filepath << "'"); + return nullptr; + } + + if(hasExtension(filepath, "raw")) { + ghoul::RawVolumeReader::ReadHints hints = readHints(hintsDictionary); + ghoul::RawVolumeReader rawReader(hints); + return rawReader.read(filepath); + } else if(hasExtension(filepath, "cdf")) { + + ghoul::opengl::Texture::FilterMode filtermode = ghoul::opengl::Texture::FilterMode::Linear; + ghoul::opengl::Texture::WrappingMode wrappingmode = ghoul::opengl::Texture::WrappingMode::ClampToEdge; + + glm::size3_t dimensions(1,1,1); + double tempValue; + if (hintsDictionary.hasKey("Dimensions.1") && + hintsDictionary.getValue("Dimensions.1", tempValue)) { + int intVal = static_cast(tempValue); + if(intVal > 0) + dimensions[0] = intVal; + } + if (hintsDictionary.hasKey("Dimensions.2") && + hintsDictionary.getValue("Dimensions.2", tempValue)) { + int intVal = static_cast(tempValue); + if(intVal > 0) + dimensions[1] = intVal; + } + if (hintsDictionary.hasKey("Dimensions.3") && + hintsDictionary.getValue("Dimensions.3", tempValue)) { + int intVal = static_cast(tempValue); + if(intVal > 0) + dimensions[2] = intVal; + } + + std::string modelString = ""; + if (hintsDictionary.hasKey("Model")) + hintsDictionary.getValue("Model", modelString); + + if(modelString == "") { + LWARNING("Model not specified."); + return nullptr; + } + + std::string variableCacheString = ""; + if (hintsDictionary.hasKey("Variable")) { + hintsDictionary.getValue("Variable", variableCacheString); + } else if(hintsDictionary.hasKey("Variables")) { + std::string xVariable, yVariable, zVariable; + bool xVar, yVar, zVar; + xVar = hintsDictionary.getValue("Variables.1", xVariable); + yVar = hintsDictionary.getValue("Variables.2", yVariable); + zVar = hintsDictionary.getValue("Variables.3", zVariable); + if (xVar && yVar && zVar) { + variableCacheString = xVariable + "." + yVariable + "." + zVariable; + } + } + + bool cache = false; + hintsDictionary.hasKey("Cache"); + if (hintsDictionary.hasKey("Cache")) + hintsDictionary.getValue("Cache", cache); + + std::stringstream ss; + ss << "." << dimensions[0] << "x" << dimensions[1] << "x" << dimensions[2] << "." << modelString << "." << variableCacheString << ".cache"; + std::string cachepath = filepath + ss.str(); + if( cache && FileSys.fileExists(cachepath)) { + + FILE* file = fopen (cachepath.c_str(), "rb"); + + int length = dimensions[0] *dimensions[1] *dimensions[2]; + float* data = new float[length]; + + for(int i = 0; i< length; i++){ + float f; + fread(&f, sizeof(float), 1, file); + data[i] = f; + } + + fclose(file); + return new ghoul::opengl::Texture(data, dimensions, ghoul::opengl::Texture::Format::Red, GL_RED, GL_FLOAT, filtermode, wrappingmode); + } + + KameleonWrapper::Model model; + if (modelString == "BATSRUS") { + model = KameleonWrapper::Model::BATSRUS; + } else if (modelString == "ENLIL") { + model = KameleonWrapper::Model::ENLIL; + } else { + LWARNING("Hints does not specify a valid 'Model'"); + return nullptr; + } + + KameleonWrapper kw(filepath, model); + std::string variableString; + if (hintsDictionary.hasKey("Variable") && hintsDictionary.getValue("Variable", variableString)) { + float* data = kw.getUniformSampledValues(variableString, dimensions); + if(cache) { + FILE* file = fopen (cachepath.c_str(), "wb"); + int length = dimensions[0] *dimensions[1] *dimensions[2]; + fwrite(data, sizeof(float), length, file); + fclose(file); + } + return new ghoul::opengl::Texture(data, dimensions, ghoul::opengl::Texture::Format::Red, GL_RED, GL_FLOAT, filtermode, wrappingmode); + } else if (hintsDictionary.hasKey("Variables")) { + std::string xVariable, yVariable, zVariable; + bool xVar, yVar, zVar; + xVar = hintsDictionary.getValue("Variables.1", xVariable); + yVar = hintsDictionary.getValue("Variables.2", yVariable); + zVar = hintsDictionary.getValue("Variables.3", zVariable); + + if (!xVar || !yVar || !zVar) { + LERROR("Error reading variables! Must be 3 and must exist in CDF data"); + } else { + + float* data = kw.getUniformSampledVectorValues(xVariable, yVariable, zVariable, dimensions); + if(cache) { + FILE* file = fopen (cachepath.c_str(), "wb"); + int length = dimensions[0] *dimensions[1] *dimensions[2]; + fwrite(data, sizeof(float), length, file); + fclose(file); + } + + return new ghoul::opengl::Texture(data, dimensions, ghoul::opengl::Texture::Format::RGBA, GL_RGBA, GL_FLOAT, filtermode, wrappingmode); + } + + } else { + LWARNING("Hints does not specify a 'Variable' or 'Variables'"); + } + } else { + LWARNING("No valid file extension."); + } + return nullptr; } -ghoul::opengl::Texture* RenderableVolume::loadVolume(const std::string& filepath, const ghoul::Dictionary& hintsDictionary) { - if( ! FileSys.fileExists(filepath)) { - LWARNING("Could not load volume, could not find '" << filepath << "'"); - return nullptr; - } - - if(hasExtension(filepath, "raw")) { - ghoul::RawVolumeReader::ReadHints hints = readHints(hintsDictionary); - ghoul::RawVolumeReader rawReader(hints); - return rawReader.read(filepath); - } else if(hasExtension(filepath, "cdf")) { - - std::string modelString; - if (hintsDictionary.hasKey("Model") && hintsDictionary.getValue("Model", modelString)) { - KameleonWrapper::Model model; - if (modelString == "BATSRUS") { - model = KameleonWrapper::Model::BATSRUS; - } else if (modelString == "ENLIL") { - model = KameleonWrapper::Model::ENLIL; - } else { - LWARNING("Hints does not specify a valid 'Model'"); - return nullptr; - } - - std::string variableString; - if (hintsDictionary.hasKey("Variable") && hintsDictionary.getValue("Variable", variableString)) { - glm::size3_t dimensions(1,1,1); - double tempValue; - if (hintsDictionary.hasKey("Dimensions.1") && hintsDictionary.getValue("Dimensions.1", tempValue)) { - int intVal = static_cast(tempValue); - if(intVal > 0) - dimensions[0] = intVal; - } - if (hintsDictionary.hasKey("Dimensions.2") && hintsDictionary.getValue("Dimensions.2", tempValue)) { - int intVal = static_cast(tempValue); - if(intVal > 0) - dimensions[1] = intVal; - } - if (hintsDictionary.hasKey("Dimensions.3") && hintsDictionary.getValue("Dimensions.3", tempValue)) { - int intVal = static_cast(tempValue); - if(intVal > 0) - dimensions[2] = intVal; - } - - KameleonWrapper kw(filepath, model); - float* data = kw.getUniformSampledValues(variableString, dimensions); - return new ghoul::opengl::Texture(data, dimensions, ghoul::opengl::Texture::Format::Red, GL_RED, GL_FLOAT); - } else { - LWARNING("Hints does not specify a 'Variable'"); - } - - - } - LWARNING("Hints does not specify a 'Model'"); - } else { - LWARNING("No valid file extension."); - } - return nullptr; +glm::vec3 RenderableVolume::getVolumeOffset( + const std::string& filepath, + const ghoul::Dictionary& hintsDictionary) { + + std::string modelString = ""; + if (hintsDictionary.hasKey("Model")) + hintsDictionary.getValue("Model", modelString); + + if(modelString == "") { + LWARNING("Model not specified."); + return glm::vec3(0); + } + KameleonWrapper::Model model; + if (modelString == "BATSRUS") { + model = KameleonWrapper::Model::BATSRUS; + } else if (modelString == "ENLIL") { + model = KameleonWrapper::Model::ENLIL; + return glm::vec3(0); + } else { + LWARNING("Hints does not specify a valid 'Model'"); + return glm::vec3(0); + } + + KameleonWrapper kw(filepath, model); + + return kw.getModelBarycenterOffset(); } ghoul::RawVolumeReader::ReadHints RenderableVolume::readHints(const ghoul::Dictionary& dictionary) { @@ -228,10 +313,15 @@ ghoul::opengl::Texture* RenderableVolume::loadTransferFunction(const std::string if ( ! FileSys.fileExists(f)) { return nullptr; } + ghoul::opengl::Texture::FilterMode filtermode = ghoul::opengl::Texture::FilterMode::Linear; + ghoul::opengl::Texture::WrappingMode wrappingmode = ghoul::opengl::Texture::WrappingMode::ClampToEdge; + // check if not a txt based texture if ( ! hasExtension(filepath, "txt")) { - return ghoul::opengl::loadTexture(f); + ghoul::opengl::Texture* t = ghoul::opengl::loadTexture(f); + t->setWrapping(wrappingmode); + return t; } // it is a txt based texture @@ -259,7 +349,7 @@ ghoul::opengl::Texture* RenderableVolume::loadTransferFunction(const std::string auto widthValidator = [](size_t in) { if(in > 0) return in; return static_cast(1); }; auto upperLowerValidator = [](float in) { return glm::clamp(in, 0.0f, 1.0f); }; - auto intensityValidator = [](float in) { if(in > 0.0f) return in; return 1.0f; }; + auto intensityValidator = [](float in) { return glm::clamp(in, 0.0f, 1.0f); }; std::string line; while (std::getline(in, line)) { @@ -294,15 +384,26 @@ ghoul::opengl::Texture* RenderableVolume::loadTransferFunction(const std::string if (mappingKeys.size() < 1) { return nullptr; } + + // for(auto key: mappingKeys) { + // glm::vec4 rgba = key.color; + // LDEBUG("i: " << key.position << ", rgba: (" << rgba[0] << ", " << rgba[1] << ", " << rgba[2] << ", " << rgba[3] << ")"); + // } + // LDEBUG("insert...."); - mappingKeys.insert(mappingKeys.begin(), {lower}); - mappingKeys.push_back({upper}); - - - for(auto key: mappingKeys) { - glm::vec4 rgba = key.color; -// LDEBUG("i: " << key.position << ", rgba: (" << rgba[0] << ", " << rgba[1] << ", " << rgba[2] << ", " << rgba[3] << ")"); + if (mappingKeys.front().position > lower){ + mappingKeys.insert(mappingKeys.begin(), {lower,mappingKeys.front().color}); } + + if (mappingKeys.back().position < upper){ + mappingKeys.push_back({upper,mappingKeys.back().color}); + } + + + // for(auto key: mappingKeys) { + // glm::vec4 rgba = key.color; + // LDEBUG("i: " << key.position << ", rgba: (" << rgba[0] << ", " << rgba[1] << ", " << rgba[2] << ", " << rgba[3] << ")"); + // } // allocate new float array with zeros float* transferFunction = new float[width*4](); @@ -310,8 +411,8 @@ ghoul::opengl::Texture* RenderableVolume::loadTransferFunction(const std::string transferFunction[i] = 0.0f; } - size_t lowerIndex = static_cast(floorf(lower*static_cast(width))); - size_t upperIndex = static_cast(floorf(upper*static_cast(width))); + size_t lowerIndex = static_cast(floorf(lower*static_cast(width-1))); + size_t upperIndex = static_cast(floorf(upper*static_cast(width-1))); // LDEBUG("width: " << width); // LDEBUG("lower: " << lower); @@ -324,9 +425,9 @@ ghoul::opengl::Texture* RenderableVolume::loadTransferFunction(const std::string auto currentKey = prevKey + 1; auto lastKey = mappingKeys.end() -1; - for (size_t i=lowerIndex; i(i)/static_cast(width); + float fpos = static_cast(i)/static_cast(width-1); if (fpos > (*currentKey).position) { prevKey = currentKey; @@ -361,16 +462,25 @@ ghoul::opengl::Texture* RenderableVolume::loadTransferFunction(const std::string //LDEBUG("["<< position <<"] " << value); } -// LDEBUG(weight << ", (" << -// transferFunction[4*i+0] << ", " << -// transferFunction[4*i+1] << ", " << -// transferFunction[4*i+2] << ", " << -// transferFunction[4*i+3] << ")"); + // LDEBUG(std::fixed << std::setw(10) << std::left << std::setprecision(8) << weight << ", (" << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+0] << ", " << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+1] << ", " << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+2] << ", " << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+3] << ")"); } + // for (int i = 0; i <= width; ++i) { + + // LDEBUG(std::fixed << "(" << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+0] << ", " << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+1] << ", " << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+2] << ", " << + // std::setw(10) << std::left << std::setprecision(8) << transferFunction[4*i+3] << ")"); + // } + return new ghoul::opengl::Texture(transferFunction, glm::size3_t(width,1,1),ghoul::opengl::Texture::Format::RGBA, - GL_RGBA, GL_FLOAT);; + GL_RGBA, GL_FLOAT,filtermode, wrappingmode); } } // namespace openspace diff --git a/src/rendering/renderablevolumecl.cpp b/src/rendering/renderablevolumecl.cpp index b87c395705..380ea1f805 100644 --- a/src/rendering/renderablevolumecl.cpp +++ b/src/rendering/renderablevolumecl.cpp @@ -1,401 +1,402 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -// open space includes -#include - -#include - -#include -#include - -#include - -#include - -namespace { - std::string _loggerCat = "RenderableVolumeCL"; -} - -namespace openspace { - -RenderableVolumeCL::RenderableVolumeCL(const ghoul::Dictionary& dictionary): - RenderableVolume(dictionary), - _backTexture(nullptr), _frontTexture(nullptr), _output(nullptr), - _clBackTexture(0), _clFrontTexture(0), _clOutput(0), - _kernelSourceFile(nullptr) { - - _kernelMutex = new std::mutex; - - _filename = ""; - if(dictionary.hasKey("Volume")) { - if(dictionary.getValue("Volume", _filename)) { - _filename = findPath(_filename); - } - } - ghoul::Dictionary hintsDictionary; - if(dictionary.hasKey("Hints")) - dictionary.getValue("Hints", hintsDictionary); - _hints = readHints(hintsDictionary); - - /* - if(dictionary.hasKey("TransferFunctions")) { - ghoul::Dictionary transferFunctions; - if(dictionary.getValue("TransferFunctions", transferFunctions)) { - auto keys = transferFunctions.keys(); - for(auto key: keys) { - std::string transferFunctionPath = ""; - if(transferFunctions.getValue(key, transferFunctionPath)) { - transferFunctionPath = findPath(transferFunctionPath); - if(transferFunctionPath != "") { - ghoul::filesystem::File* tmp = new ghoul::filesystem::File(transferFunctionPath, false); - ghoul::opengl::Texture* tmpTexture = ghoul::opengl::loadTexture(tmp->path()); - - _transferFunctions.push_back(tmpTexture); - _transferFunctionsFiles.push_back(tmp); - } - } - } - } - } - */ - - if(dictionary.hasKey("UpdateOnSave")) { - dictionary.getValue("UpdateOnSave", _kernelUpdateOnSave); - } - - /* - if(dictionary.hasKey("KernelOptions")) { - using namespace ghoul::opencl; - ghoul::Dictionary kernelOptions; - if(dictionary.getValue("KernelOptions", kernelOptions)) { - auto keys = kernelOptions.keys(); - for(auto key: keys) { - bool value = false; - if(kernelOptions.getValue(key, value)) { - if(key == "DenormsAreZero") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::DenormsAreZero, value)); - } else if(key == "FastRelaxedMath") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::FastRelaxedMath, value)); - } else if(key == "FiniteMathOnly") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::FiniteMathOnly, value)); - } else if(key == "KernelArgInfo") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::KernelArgInfo, value)); - } else if(key == "MadEnable") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::MadEnable, value)); - } else if(key == "NoSignedZero") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::NoSignedZero, value)); - } else if(key == "OptDisable") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::OptDisable, value)); - } else if(key == "SinglePrecisionConstant") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::SinglePrecisionConstant, value)); - } else if(key == "StrictAliasing") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::StrictAliasing, value)); - } else if(key == "UnsafeMathOptimizations") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::UnsafeMathOptimizations, value)); - } - } - } - } - } - */ - - std::string kernelPath = ""; - if (dictionary.hasKey("Kernel")) { - if(dictionary.getValue("Kernel", kernelPath)) { - kernelPath = findPath(kernelPath); - } - } - if (kernelPath != "") { - _kernelSourceFile = new ghoul::filesystem::File(kernelPath, false); - } - -} - -RenderableVolumeCL::~RenderableVolumeCL() { - deinitialize(); - delete _kernelMutex; -} - -bool RenderableVolumeCL::initialize() { - assert(_filename != ""); - // ------ VOLUME READING ---------------- - ghoul::RawVolumeReader rawReader(_hints); - _volume = rawReader.read(_filename); - glm::size3_t d = _volume->dimensions(); - - // ------ SETUP GEOMETRY ---------------- - const GLfloat size = 1.0f; - const GLfloat vertex_texcoord_data[] = { // square of two triangles (sigh) - // x y z s t - -size, -size, 0.0f, 0.0f, 0.0f, - size, size, 0.0f, 1.0f, 1.0f, - -size, size, 0.0f, 0.0f, 1.0f, - -size, -size, 0.0f, 0.0f, 0.0f, - size, -size, 0.0f, 1.0f, 0.0f, - size, size, 0.0f, 1.0f, 1.0f - }; - - GLuint vertexPositionBuffer; - glGenVertexArrays(1, &_screenQuad); // generate array - glBindVertexArray(_screenQuad); // bind array - glGenBuffers(1, &vertexPositionBuffer); // generate buffer - glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_texcoord_data), vertex_texcoord_data, GL_STATIC_DRAW); - - // Vertex positions - GLuint vertexLocation = 2; - glEnableVertexAttribArray(vertexLocation); - glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), reinterpret_cast(0)); - - // Texture coordinates - GLuint texcoordLocation = 0; - glEnableVertexAttribArray(texcoordLocation); - glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void*)(3*sizeof(GLfloat))); - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer - glBindVertexArray(0); //unbind array - - _boundingBox = new sgct_utils::SGCTBox(1.0f, sgct_utils::SGCTBox::Regular); - - // ------ SETUP SHADERS ----------------- - // TODO error control or better design pattern - OsEng.ref().configurationManager().getValue("RaycastProgram", _fboProgram); - OsEng.ref().configurationManager().getValue("Quad", _quadProgram); - - // ------ SETUP FBO --------------------- - _fbo = new ghoul::opengl::FramebufferObject(); - _fbo->activate(); - - size_t x = sgct::Engine::instance()->getActiveXResolution(); - size_t y = sgct::Engine::instance()->getActiveYResolution(); - _backTexture = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); - _frontTexture = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); - _output = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); - _backTexture->uploadTexture(); - _frontTexture->uploadTexture(); - _output->uploadTexture(); - _fbo->attachTexture(_backTexture, GL_COLOR_ATTACHMENT0); - _fbo->attachTexture(_frontTexture, GL_COLOR_ATTACHMENT1); - - _fbo->deactivate(); - - _context = OsEng.clContext(); - _commands = _context.createCommandQueue(); - - _clBackTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *_backTexture); - _clFrontTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *_frontTexture); - _clVolume = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *_volume); - _clOutput = _context.createTextureFromGLTexture(CL_MEM_WRITE_ONLY, *_output); - - auto privateCallback = [this](const ghoul::filesystem::File& file) { - safeKernelCompilation(); - }; - - _kernelSourceFile = new ghoul::filesystem::File(_kernelSourceFile->path(), false); - if(_kernelUpdateOnSave) - _kernelSourceFile->setCallback(privateCallback); - - safeKernelCompilation(); - - size_t local_x = 32; - size_t local_y = 32; - while (local_x > 1) { - if(x % local_x == 0) - break; - local_x /= 2; - } - while (local_y > 1) { - if(y % local_y == 0) - break; - local_y /= 2; - } - _ws = new ghoul::opencl::CLWorkSize ({x,y}, {local_x,local_y}); - - return true; - -} - -bool RenderableVolumeCL::deinitialize() { - - delete _ws; - _ws = nullptr; - - return true; -} - -void RenderableVolumeCL::render(const Camera *camera, const psc &thisPosition) { - - if( ! _kernel.isValidKernel()) - return; - - float speed = 50.0f; - float time = sgct::Engine::getTime(); - glm::mat4 transform = camera->viewProjectionMatrix(); - - double factor = pow(10.0,thisPosition[3]); - transform = glm::translate(transform, glm::vec3(thisPosition[0]*factor, thisPosition[1]*factor, thisPosition[2]*factor)); - transform = glm::rotate(transform, time*speed, glm::vec3(0.0f, 1.0f, 0.0f)); - - - if(_kernel.isValidKernel()) { - _stepSize = 0.01f; - - // ------ DRAW TO FBO ------------------- - GLuint sgctFBO = ghoul::opengl::FramebufferObject::getActiveObject(); // Save SGCTs main FBO - _fbo->activate(); - _fboProgram->activate(); - _fboProgram->setUniform("modelViewProjection", transform); - - // Draw backface - glDrawBuffer(GL_COLOR_ATTACHMENT0); - glClearColor(0.2f, 0.2f, 0.2f, 0); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - _boundingBox->draw(); - glDisable(GL_CULL_FACE); - - // Draw frontface - glDrawBuffer(GL_COLOR_ATTACHMENT1); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.2f, 0.2f, 0.2f, 0); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - _boundingBox->draw(); - glDisable(GL_CULL_FACE); - - _fboProgram->deactivate(); - _fbo->deactivate(); - - // ------ DRAW TO SCREEN ---------------- - glBindFramebuffer(GL_FRAMEBUFFER, sgctFBO); // Re-bind SGCTs main FBO - - - - glFinish(); - _commands.enqueueKernelBlocking(_kernel, *_ws); - _commands.finish(); - _quadProgram->activate(); - glActiveTexture(GL_TEXTURE0); - _output->bind(); - glClearColor(0.0f, 0.0f, 0.0f, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - - _quadProgram->deactivate(); - - } - - - -} - -void RenderableVolumeCL::update() { - -} - -void RenderableVolumeCL::safeKernelCompilation() { - std::string _loggerCat = "RenderableVolumeCL::safeKernelCompilation"; - if(_context.isValidContext()) { - - ghoul::opencl::CLProgram tmpProgram = _context.createProgram(_kernelSourceFile->path()); - tmpProgram.setOption(ghoul::opencl::CLProgram::Option::OptDisable, true); - tmpProgram.setOption(ghoul::opencl::CLProgram::Option::KernelArgInfo, true); - if(tmpProgram.build()) { - ghoul::opencl::CLKernel tmpKernel = tmpProgram.createKernel("volumeraycaster"); - if(tmpKernel.isValidKernel()) { - tmpKernel.setArgument(0, &_clFrontTexture); - tmpKernel.setArgument(1, &_clBackTexture); - tmpKernel.setArgument(2, &_clVolume); - tmpKernel.setArgument(3, &_clOutput); - - // do the actual assignment behind locked doors - _kernelMutex->lock(); - _program = tmpProgram; - _kernel = tmpKernel; - _kernelMutex->unlock(); - - LDEBUG("Done updating kernel"); - } else { - LWARNING("Kernel is not valid"); - } - } else { - LWARNING("Could not build CLProgram"); - } - } else { - LWARNING("No valid CLContext"); - } -} - /* -void RenderableVolumeCL::safeUpdateTexture(const ghoul::filesystem::File& file) { - int fileID = 0; - for (fileID = 0; fileID < _transferFunctionsFiles.size(); ++fileID) { - if (_transferFunctionsFiles.at(fileID) == &file) { - //LDEBUG("Transferfunction found at id " << fileID); - break; - } - } - if(fileID == _transferFunctionsFiles.size()) - return; - - LDEBUG("Updating transferfunction"); - // create the new texture - ghoul::opengl::Texture* newTexture = ghoul::opengl::loadTexture(file.path()); - - if(newTexture) { - - // upload the new texture and create a cl memory - newTexture->uploadTexture(); - cl_mem clNewTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *newTexture); - - if(clNewTexture == 0) { - delete newTexture; - return; - } - - // everything is ok, critical point to replace current texture pointers - _textureLock->lock(); - - // deallocate current texture - delete _transferFunctions.at(fileID); - clReleaseMemObject(_clTransferFunctions.at(fileID)); - - // set the new texture - _transferFunctions.at(fileID) = newTexture; - _clTransferFunctions.at(fileID) = clNewTexture; - - // update kernel - // __kernel arguments(front, back, output, [_volumes], .. fileID)) - _kernel.setArgument(3 + _volumes.size() + fileID, &clNewTexture); - - // end of critical section - _textureLock->unlock(); - } -} -*/ - -} // namespace openspace \ No newline at end of file +// This is still in the repository to be cannibalized for a possible rewrite (ab) +///***************************************************************************************** +// * * +// * OpenSpace * +// * * +// * Copyright (c) 2014 * +// * * +// * Permission is hereby granted, free of charge, to any person obtaining a copy of this * +// * software and associated documentation files (the "Software"), to deal in the Software * +// * without restriction, including without limitation the rights to use, copy, modify, * +// * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +// * permit persons to whom the Software is furnished to do so, subject to the following * +// * conditions: * +// * * +// * The above copyright notice and this permission notice shall be included in all copies * +// * or substantial portions of the Software. * +// * * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +// * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +// * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +// * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +// * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +// * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +// ****************************************************************************************/ +// +//// open space includes +//#include +// +//#include +// +//#include +//#include +// +//#include +// +//#include +// +//namespace { +// std::string _loggerCat = "RenderableVolumeCL"; +//} +// +//namespace openspace { +// +//RenderableVolumeCL::RenderableVolumeCL(const ghoul::Dictionary& dictionary): +// RenderableVolume(dictionary), +// _backTexture(nullptr), _frontTexture(nullptr), _output(nullptr), +// _clBackTexture(0), _clFrontTexture(0), _clOutput(0), +// _kernelSourceFile(nullptr) { +// +// _kernelMutex = new std::mutex; +// +// _filename = ""; +// if(dictionary.hasKey("Volume")) { +// if(dictionary.getValue("Volume", _filename)) { +// _filename = findPath(_filename); +// } +// } +// ghoul::Dictionary hintsDictionary; +// if(dictionary.hasKey("Hints")) +// dictionary.getValue("Hints", hintsDictionary); +// _hints = readHints(hintsDictionary); +// +// /* +// if(dictionary.hasKey("TransferFunctions")) { +// ghoul::Dictionary transferFunctions; +// if(dictionary.getValue("TransferFunctions", transferFunctions)) { +// auto keys = transferFunctions.keys(); +// for(auto key: keys) { +// std::string transferFunctionPath = ""; +// if(transferFunctions.getValue(key, transferFunctionPath)) { +// transferFunctionPath = findPath(transferFunctionPath); +// if(transferFunctionPath != "") { +// ghoul::filesystem::File* tmp = new ghoul::filesystem::File(transferFunctionPath, false); +// ghoul::opengl::Texture* tmpTexture = ghoul::opengl::loadTexture(tmp->path()); +// +// _transferFunctions.push_back(tmpTexture); +// _transferFunctionsFiles.push_back(tmp); +// } +// } +// } +// } +// } +// */ +// +// if(dictionary.hasKey("UpdateOnSave")) { +// dictionary.getValue("UpdateOnSave", _kernelUpdateOnSave); +// } +// +// /* +// if(dictionary.hasKey("KernelOptions")) { +// using namespace ghoul::opencl; +// ghoul::Dictionary kernelOptions; +// if(dictionary.getValue("KernelOptions", kernelOptions)) { +// auto keys = kernelOptions.keys(); +// for(auto key: keys) { +// bool value = false; +// if(kernelOptions.getValue(key, value)) { +// if(key == "DenormsAreZero") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::DenormsAreZero, value)); +// } else if(key == "FastRelaxedMath") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::FastRelaxedMath, value)); +// } else if(key == "FiniteMathOnly") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::FiniteMathOnly, value)); +// } else if(key == "KernelArgInfo") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::KernelArgInfo, value)); +// } else if(key == "MadEnable") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::MadEnable, value)); +// } else if(key == "NoSignedZero") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::NoSignedZero, value)); +// } else if(key == "OptDisable") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::OptDisable, value)); +// } else if(key == "SinglePrecisionConstant") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::SinglePrecisionConstant, value)); +// } else if(key == "StrictAliasing") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::StrictAliasing, value)); +// } else if(key == "UnsafeMathOptimizations") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::UnsafeMathOptimizations, value)); +// } +// } +// } +// } +// } +// */ +// +// std::string kernelPath = ""; +// if (dictionary.hasKey("Kernel")) { +// if(dictionary.getValue("Kernel", kernelPath)) { +// kernelPath = findPath(kernelPath); +// } +// } +// if (kernelPath != "") { +// _kernelSourceFile = new ghoul::filesystem::File(kernelPath, false); +// } +// +//} +// +//RenderableVolumeCL::~RenderableVolumeCL() { +// deinitialize(); +// delete _kernelMutex; +//} +// +//bool RenderableVolumeCL::initialize() { +// assert(_filename != ""); +// // ------ VOLUME READING ---------------- +// ghoul::RawVolumeReader rawReader(_hints); +// _volume = rawReader.read(_filename); +// glm::size3_t d = _volume->dimensions(); +// +// // ------ SETUP GEOMETRY ---------------- +// const GLfloat size = 1.0f; +// const GLfloat vertex_texcoord_data[] = { // square of two triangles (sigh) +// // x y z s t +// -size, -size, 0.0f, 0.0f, 0.0f, +// size, size, 0.0f, 1.0f, 1.0f, +// -size, size, 0.0f, 0.0f, 1.0f, +// -size, -size, 0.0f, 0.0f, 0.0f, +// size, -size, 0.0f, 1.0f, 0.0f, +// size, size, 0.0f, 1.0f, 1.0f +// }; +// +// GLuint vertexPositionBuffer; +// glGenVertexArrays(1, &_screenQuad); // generate array +// glBindVertexArray(_screenQuad); // bind array +// glGenBuffers(1, &vertexPositionBuffer); // generate buffer +// glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer +// glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_texcoord_data), vertex_texcoord_data, GL_STATIC_DRAW); +// +// // Vertex positions +// GLuint vertexLocation = 2; +// glEnableVertexAttribArray(vertexLocation); +// glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), reinterpret_cast(0)); +// +// // Texture coordinates +// GLuint texcoordLocation = 0; +// glEnableVertexAttribArray(texcoordLocation); +// glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void*)(3*sizeof(GLfloat))); +// +// glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer +// glBindVertexArray(0); //unbind array +// +// _boundingBox = new sgct_utils::SGCTBox(1.0f, sgct_utils::SGCTBox::Regular); +// +// // ------ SETUP SHADERS ----------------- +// // TODO error control or better design pattern +// OsEng.ref().configurationManager().getValue("RaycastProgram", _fboProgram); +// OsEng.ref().configurationManager().getValue("Quad", _quadProgram); +// +// // ------ SETUP FBO --------------------- +// _fbo = new ghoul::opengl::FramebufferObject(); +// _fbo->activate(); +// +// size_t x = sgct::Engine::instance()->getActiveXResolution(); +// size_t y = sgct::Engine::instance()->getActiveYResolution(); +// _backTexture = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); +// _frontTexture = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); +// _output = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); +// _backTexture->uploadTexture(); +// _frontTexture->uploadTexture(); +// _output->uploadTexture(); +// _fbo->attachTexture(_backTexture, GL_COLOR_ATTACHMENT0); +// _fbo->attachTexture(_frontTexture, GL_COLOR_ATTACHMENT1); +// +// _fbo->deactivate(); +// +// _context = OsEng.clContext(); +// _commands = _context.createCommandQueue(); +// +// _clBackTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *_backTexture); +// _clFrontTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *_frontTexture); +// _clVolume = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *_volume); +// _clOutput = _context.createTextureFromGLTexture(CL_MEM_WRITE_ONLY, *_output); +// +// auto privateCallback = [this](const ghoul::filesystem::File& file) { +// safeKernelCompilation(); +// }; +// +// _kernelSourceFile = new ghoul::filesystem::File(_kernelSourceFile->path(), false); +// if(_kernelUpdateOnSave) +// _kernelSourceFile->setCallback(privateCallback); +// +// safeKernelCompilation(); +// +// size_t local_x = 32; +// size_t local_y = 32; +// while (local_x > 1) { +// if(x % local_x == 0) +// break; +// local_x /= 2; +// } +// while (local_y > 1) { +// if(y % local_y == 0) +// break; +// local_y /= 2; +// } +// _ws = new ghoul::opencl::CLWorkSize ({x,y}, {local_x,local_y}); +// +// return true; +// +//} +// +//bool RenderableVolumeCL::deinitialize() { +// +// delete _ws; +// _ws = nullptr; +// +// return true; +//} +// +//void RenderableVolumeCL::render(const Camera *camera, const psc &thisPosition) { +// +// if( ! _kernel.isValidKernel()) +// return; +// +// float speed = 50.0f; +// float time = sgct::Engine::getTime(); +// glm::mat4 transform = camera->viewProjectionMatrix(); +// +// double factor = pow(10.0,thisPosition[3]); +// transform = glm::translate(transform, glm::vec3(thisPosition[0]*factor, thisPosition[1]*factor, thisPosition[2]*factor)); +// transform = glm::rotate(transform, time*speed, glm::vec3(0.0f, 1.0f, 0.0f)); +// +// +// if(_kernel.isValidKernel()) { +// _stepSize = 0.01f; +// +// // ------ DRAW TO FBO ------------------- +// GLuint sgctFBO = ghoul::opengl::FramebufferObject::getActiveObject(); // Save SGCTs main FBO +// _fbo->activate(); +// _fboProgram->activate(); +// _fboProgram->setUniform("modelViewProjection", transform); +// +// // Draw backface +// glDrawBuffer(GL_COLOR_ATTACHMENT0); +// glClearColor(0.2f, 0.2f, 0.2f, 0); +// glClear(GL_COLOR_BUFFER_BIT); +// glEnable(GL_CULL_FACE); +// glCullFace(GL_FRONT); +// _boundingBox->draw(); +// glDisable(GL_CULL_FACE); +// +// // Draw frontface +// glDrawBuffer(GL_COLOR_ATTACHMENT1); +// glClear(GL_COLOR_BUFFER_BIT); +// glClearColor(0.2f, 0.2f, 0.2f, 0); +// glEnable(GL_CULL_FACE); +// glCullFace(GL_BACK); +// _boundingBox->draw(); +// glDisable(GL_CULL_FACE); +// +// _fboProgram->deactivate(); +// _fbo->deactivate(); +// +// // ------ DRAW TO SCREEN ---------------- +// glBindFramebuffer(GL_FRAMEBUFFER, sgctFBO); // Re-bind SGCTs main FBO +// +// +// +// glFinish(); +// _commands.enqueueKernelBlocking(_kernel, *_ws); +// _commands.finish(); +// _quadProgram->activate(); +// glActiveTexture(GL_TEXTURE0); +// _output->bind(); +// glClearColor(0.0f, 0.0f, 0.0f, 0); +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +// glBindVertexArray(_screenQuad); +// glDrawArrays(GL_TRIANGLES, 0, 6); +// glBindVertexArray(0); +// +// _quadProgram->deactivate(); +// +// } +// +// +// +//} +// +//void RenderableVolumeCL::update() { +// +//} +// +//void RenderableVolumeCL::safeKernelCompilation() { +// std::string _loggerCat = "RenderableVolumeCL::safeKernelCompilation"; +// if(_context.isValidContext()) { +// +// ghoul::opencl::CLProgram tmpProgram = _context.createProgram(_kernelSourceFile->path()); +// tmpProgram.setOption(ghoul::opencl::CLProgram::Option::OptDisable, true); +// tmpProgram.setOption(ghoul::opencl::CLProgram::Option::KernelArgInfo, true); +// if(tmpProgram.build()) { +// ghoul::opencl::CLKernel tmpKernel = tmpProgram.createKernel("volumeraycaster"); +// if(tmpKernel.isValidKernel()) { +// tmpKernel.setArgument(0, &_clFrontTexture); +// tmpKernel.setArgument(1, &_clBackTexture); +// tmpKernel.setArgument(2, &_clVolume); +// tmpKernel.setArgument(3, &_clOutput); +// +// // do the actual assignment behind locked doors +// _kernelMutex->lock(); +// _program = tmpProgram; +// _kernel = tmpKernel; +// _kernelMutex->unlock(); +// +// LDEBUG("Done updating kernel"); +// } else { +// LWARNING("Kernel is not valid"); +// } +// } else { +// LWARNING("Could not build CLProgram"); +// } +// } else { +// LWARNING("No valid CLContext"); +// } +//} +// /* +//void RenderableVolumeCL::safeUpdateTexture(const ghoul::filesystem::File& file) { +// int fileID = 0; +// for (fileID = 0; fileID < _transferFunctionsFiles.size(); ++fileID) { +// if (_transferFunctionsFiles.at(fileID) == &file) { +// //LDEBUG("Transferfunction found at id " << fileID); +// break; +// } +// } +// if(fileID == _transferFunctionsFiles.size()) +// return; +// +// LDEBUG("Updating transferfunction"); +// // create the new texture +// ghoul::opengl::Texture* newTexture = ghoul::opengl::loadTexture(file.path()); +// +// if(newTexture) { +// +// // upload the new texture and create a cl memory +// newTexture->uploadTexture(); +// cl_mem clNewTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *newTexture); +// +// if(clNewTexture == 0) { +// delete newTexture; +// return; +// } +// +// // everything is ok, critical point to replace current texture pointers +// _textureLock->lock(); +// +// // deallocate current texture +// delete _transferFunctions.at(fileID); +// clReleaseMemObject(_clTransferFunctions.at(fileID)); +// +// // set the new texture +// _transferFunctions.at(fileID) = newTexture; +// _clTransferFunctions.at(fileID) = clNewTexture; +// +// // update kernel +// // __kernel arguments(front, back, output, [_volumes], .. fileID)) +// _kernel.setArgument(3 + _volumes.size() + fileID, &clNewTexture); +// +// // end of critical section +// _textureLock->unlock(); +// } +//} +//*/ +// +//} // namespace openspace \ No newline at end of file diff --git a/src/rendering/renderablevolumeexpert.cpp b/src/rendering/renderablevolumeexpert.cpp index c3f268ae4a..49b22aab65 100644 --- a/src/rendering/renderablevolumeexpert.cpp +++ b/src/rendering/renderablevolumeexpert.cpp @@ -1,531 +1,534 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -// open space includes -#include - -#include - -#include -#include -#include -#include - -#include - -namespace { - std::string _loggerCat = "RenderableVolumeExpert"; - - size_t countKernelArguments(ghoul::opencl::CLKernel& kernel) { - - using ghoul::opencl::CLKernel; - CLKernel::AddressQualifier adq; - CLKernel::AccessQualifier acq; - CLKernel::TypeQualifier atq; - - size_t arguments = 0; - do { - adq = kernel.argumentAddressQualifier(arguments); - acq = kernel.argumentAccessQualifier(arguments); - atq = kernel.argumentTypeQualifier(arguments); - ++arguments; - } while (adq != CLKernel::AddressQualifier::Error && - acq != CLKernel::AccessQualifier::Error && - atq != CLKernel::TypeQualifier::Error); - - return arguments - 1; - } -} - -namespace openspace { - -RenderableVolumeExpert::RenderableVolumeExpert(const ghoul::Dictionary& dictionary): - RenderableVolume(dictionary), - _output(nullptr), - _clBackTexture(0), _clFrontTexture(0), _clOutput(0), - _kernelSourceFile(nullptr), _programUpdateOnSave(false), _colorBoxRenderer(nullptr), - _boxScaling(1.0,1.0,1.0) { - - _kernelLock = new std::mutex; - _textureLock = new std::mutex; - - if(dictionary.hasKey("Volumes")) { - ghoul::Dictionary volumes; - if(dictionary.getValue("Volumes", volumes)) { - auto keys = volumes.keys(); - for(auto key: keys) { - ghoul::Dictionary volume; - if(volumes.getValue(key, volume)) { - if (volume.hasKey("File")) { - std::string file = ""; - if (volume.getValue("File", file)) { - file = findPath(file); - if (file != "") { - - // parse hints - ghoul::Dictionary hintsDictionary; - if(volume.hasKey("Hints")) - volume.getValue("Hints", hintsDictionary); - - _volumePaths.push_back(file); - _volumeHints.push_back(hintsDictionary); - } - } - } - } - } - } - } - - if(dictionary.hasKey("TransferFunctions")) { - ghoul::Dictionary transferFunctions; - if(dictionary.getValue("TransferFunctions", transferFunctions)) { - auto keys = transferFunctions.keys(); - for(auto key: keys) { - std::string transferFunctionPath = ""; - if(transferFunctions.getValue(key, transferFunctionPath)) { - transferFunctionPath = findPath(transferFunctionPath); - ghoul::opengl::Texture* tmpTexture = loadTransferFunction(transferFunctionPath); - if(tmpTexture) { - ghoul::filesystem::File* tmp = new ghoul::filesystem::File(transferFunctionPath, false); - _transferFunctions.push_back(tmpTexture); - _transferFunctionsFiles.push_back(tmp); - } - } - } - } - } - - std::string kernelPath = ""; - if (dictionary.hasKey("Kernel")) { - ghoul::Dictionary kernelDictionary; - if(dictionary.getValue("Kernel", kernelDictionary)) { - if(kernelDictionary.getValue("Source", kernelPath)) { - kernelPath = findPath(kernelPath); - - } - if(kernelDictionary.hasKey("UpdateOnSave")) { - kernelDictionary.getValue("UpdateOnSave", _programUpdateOnSave); - } - - if(kernelDictionary.hasKey("Options")) { - using namespace ghoul::opencl; - ghoul::Dictionary kernelOptions; - if(kernelDictionary.getValue("Options", kernelOptions)) { - auto keys = kernelOptions.keys(); - for(auto key: keys) { - bool value = false; - if(kernelOptions.getValue(key, value)) { - if(key == "DenormsAreZero") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::DenormsAreZero, value)); - } else if(key == "FastRelaxedMath") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::FastRelaxedMath, value)); - } else if(key == "FiniteMathOnly") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::FiniteMathOnly, value)); - } else if(key == "KernelArgInfo") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::KernelArgInfo, value)); - } else if(key == "MadEnable") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::MadEnable, value)); - } else if(key == "NoSignedZero") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::NoSignedZero, value)); - } else if(key == "OptDisable") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::OptDisable, value)); - } else if(key == "SinglePrecisionConstant") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::SinglePrecisionConstant, value)); - } else if(key == "StrictAliasing") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::StrictAliasing, value)); - } else if(key == "UnsafeMathOptimizations") { - _kernelOptions.push_back(std::make_pair(CLProgram::Option::UnsafeMathOptimizations, value)); - } - } - } - } - } - - ghoul::Dictionary includeDictionary; - if (kernelDictionary.hasKey("Includes") && kernelDictionary.getValue("Includes", includeDictionary)) { - auto keys = includeDictionary.keys(); - for(auto key: keys) { - std::string includePath; - if(includeDictionary.getValue(key, includePath)) { - if(FileSys.directoryExists(includePath)) { - _kernelIncludes.push_back(absPath(includePath)); - } - } - } - } - - ghoul::Dictionary defineDictionary; - if (kernelDictionary.hasKey("Definitions") && kernelDictionary.getValue("Definitions", defineDictionary)) { - auto keys = defineDictionary.keys(); - for(auto key: keys) { - std::string defintion; - if(defineDictionary.getValue(key, defintion)) { - _kernelDefinitions.push_back(std::make_pair(key, defintion)); - } - } - } - } - } - if (kernelPath != "") { - _kernelSourceFile = new ghoul::filesystem::File(kernelPath, false); - } - - _colorBoxRenderer = new VolumeRaycasterBox(); - double tempValue; - if(dictionary.hasKey("BoxScaling.1") && dictionary.getValue("BoxScaling.1", tempValue)) { - if(tempValue > 0.0) { - _boxScaling[0] = tempValue; - } - } - if(dictionary.hasKey("BoxScaling.2") && dictionary.getValue("BoxScaling.2", tempValue)) { - if(tempValue > 0.0) { - _boxScaling[1] = tempValue; - } - } - if(dictionary.hasKey("BoxScaling.3") && dictionary.getValue("BoxScaling.3", tempValue)) { - if(tempValue > 0.0) { - _boxScaling[2] = tempValue; - } - } - - setBoundingSphere(PowerScaledScalar::CreatePSS(_boxScaling.length())); -} - -RenderableVolumeExpert::~RenderableVolumeExpert() { - deinitialize(); - delete _textureLock; - delete _kernelLock; -} - -bool RenderableVolumeExpert::initialize() { - if(_kernelSourceFile == nullptr) { - LERROR("Could not find the kernel file!"); - return false; - } - - _context = OsEng.clContext(); - - auto textureCallback = [this](const ghoul::filesystem::File& file) { - safeUpdateTexture(file); - }; - auto kernelCallback = [this](const ghoul::filesystem::File& file) { - safeKernelCompilation(); - }; - - for(auto texture: _transferFunctions) { - texture->uploadTexture(); - cl_mem transferMem = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *texture); - _clTransferFunctions.push_back(transferMem); - } - if(_programUpdateOnSave) { - _kernelSourceFile->setCallback(kernelCallback); - for(auto texture: _transferFunctionsFiles) { - texture->setCallback(textureCallback); - } - } - - for (int i = 0; i < _volumePaths.size(); ++i) { - ghoul::opengl::Texture* volume = loadVolume(_volumePaths.at(i), _volumeHints.at(i)); - if(volume) { - volume->uploadTexture(); - - LDEBUG("Creating CL texture from GL texture with path '" << _volumePaths.at(i) << "'"); - cl_mem volumeTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *volume); - - _volumes.push_back(volume); - _clVolumes.push_back(volumeTexture); - } - } - - // ------ SETUP GEOMETRY ---------------- - const GLfloat size = 1.0f; - const GLfloat vertex_texcoord_data[] = { // square of two triangles (sigh) - // x y z s t - -size, -size, 0.0f, 0.0f, 0.0f, - size, size, 0.0f, 1.0f, 1.0f, - -size, size, 0.0f, 0.0f, 1.0f, - -size, -size, 0.0f, 0.0f, 0.0f, - size, -size, 0.0f, 1.0f, 0.0f, - size, size, 0.0f, 1.0f, 1.0f - }; - - GLuint vertexPositionBuffer; - glGenVertexArrays(1, &_screenQuad); // generate array - glBindVertexArray(_screenQuad); // bind array - glGenBuffers(1, &vertexPositionBuffer); // generate buffer - glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_texcoord_data), vertex_texcoord_data, GL_STATIC_DRAW); - - // Vertex positions - GLuint vertexLocation = 2; - glEnableVertexAttribArray(vertexLocation); - glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), reinterpret_cast(0)); - - // Texture coordinates - GLuint texcoordLocation = 0; - glEnableVertexAttribArray(texcoordLocation); - glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void*)(3*sizeof(GLfloat))); - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer - glBindVertexArray(0); //unbind array - - if( ! OsEng.ref().configurationManager().getValue("Quad", _quadProgram)) { - LERROR("Could not find 'Quad'"); - return false; - } - - _colorBoxRenderer->initialize(); - glm::size2_t dimensions = _colorBoxRenderer->dimensions(); - ghoul::opengl::Texture* backTexture = _colorBoxRenderer->backFace(); - ghoul::opengl::Texture* frontTexture = _colorBoxRenderer->frontFace(); - _output = new ghoul::opengl::Texture(glm::size3_t(dimensions[0],dimensions[1],1)); - _output->uploadTexture(); - - _context = OsEng.clContext(); - _commands = _context.createCommandQueue(); - - _clBackTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *backTexture); - _clFrontTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *frontTexture); - _clOutput = _context.createTextureFromGLTexture(CL_MEM_WRITE_ONLY, *_output); - - // Compile kernels - safeKernelCompilation(); - - // create work group - size_t local_x = 32; - size_t local_y = 32; - while (local_x > 1) { - if(dimensions[0] % local_x == 0) - break; - local_x /= 2; - } - while (local_y > 1) { - if(dimensions[1] % local_y == 0) - break; - local_y /= 2; - } - _ws = new ghoul::opencl::CLWorkSize({dimensions[0],dimensions[1]}, {local_x,local_y}); - - return true; -} - -bool RenderableVolumeExpert::deinitialize() { - - - return true; -} - -void RenderableVolumeExpert::render(const Camera *camera, const psc &thisPosition) { - if( ! _kernel.isValidKernel()) - return; - - glm::mat4 transform = camera->viewProjectionMatrix(); - glm::mat4 camTransform = camera->viewRotationMatrix(); - psc relative = thisPosition-camera->position(); - - transform = transform*camTransform; - transform = glm::translate(transform, relative.vec3()); - transform = glm::scale(transform, _boxScaling); - - _colorBoxRenderer->render(transform); - - _textureLock->lock(); - _kernelLock->lock(); - - // tell opengl to finish everything before opencl takes ownerhip (uses) the textures - glFinish(); - - // Aquire GL objects - _commands.enqueueAcquireGLObjects(_clBackTexture); - _commands.enqueueAcquireGLObjects(_clFrontTexture); - _commands.enqueueAcquireGLObjects(_clOutput); - _commands.enqueueAcquireGLObjects(_clVolumes); - _commands.enqueueAcquireGLObjects(_clTransferFunctions); - - _commands.enqueueKernelBlocking(_kernel, *_ws); - _commands.finish(); - - // Release GL objects - _commands.enqueueReleaseGLObjects(_clBackTexture); - _commands.enqueueReleaseGLObjects(_clFrontTexture); - _commands.enqueueReleaseGLObjects(_clOutput); - _commands.enqueueReleaseGLObjects(_clVolumes); - _commands.enqueueReleaseGLObjects(_clTransferFunctions); - - _quadProgram->activate(); - glActiveTexture(GL_TEXTURE0); - _output->bind(); - - // enable blending - glEnable(GL_BLEND); - glDisable(GL_DEPTH_TEST); - glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); - - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - - _kernelLock->unlock(); - _textureLock->unlock(); - - // disable blending - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glBlendFunc(GL_ONE, GL_ZERO); - - _quadProgram->deactivate(); -} - -void RenderableVolumeExpert::update() { - -} - -void RenderableVolumeExpert::safeKernelCompilation() { - if(_context.isValidContext()) { - - ghoul::opencl::CLProgram tmpProgram = _context.createProgram(_kernelSourceFile->path()); - for(auto option: _kernelOptions) { - tmpProgram.setOption(option.first, option.second); - } - - for(auto defintion: _kernelDefinitions) { - tmpProgram.addDefinition(defintion.first, defintion.second); - } - - // add the include directories - tmpProgram.addIncludeDirectory(_kernelIncludes); - - if(tmpProgram.build()) { - ghoul::opencl::CLKernel tmpKernel = tmpProgram.createKernel("volumeraycaster"); - if(tmpKernel.isValidKernel()) { - - auto begin = _kernelOptions.begin(); - auto end = _kernelOptions.end(); - auto f = std::find(begin, end, std::make_pair(ghoul::opencl::CLProgram::Option::KernelArgInfo, true)); - - int maxarguments = 1024; - bool argumentError = false; - if (f != end) { - LDEBUG("Checking argument types"); - - using ghoul::opencl::CLKernel; - maxarguments = countKernelArguments(tmpKernel); - - for (int i = 3; i maxarguments) { - LWARNING("More arguments set than kernel accepts."); - } - - // do the actual assignment behind locked doors - _kernelLock->lock(); - _program = tmpProgram; - _kernel = tmpKernel; - _kernelLock->unlock(); - LDEBUG("Done updating kernel"); - } - } - } -} - -void RenderableVolumeExpert::safeUpdateTexture(const ghoul::filesystem::File& file) { - int fileID = 0; - for (fileID = 0; fileID < _transferFunctionsFiles.size(); ++fileID) { - if (_transferFunctionsFiles.at(fileID) == &file) { - //LDEBUG("Transferfunction found at id " << fileID); - break; - } - } - if(fileID == _transferFunctionsFiles.size()) - return; - - LDEBUG("Updating transferfunction"); - - // create the new texture - ghoul::opengl::Texture* newTexture = loadTransferFunction(file.path()); - - if(newTexture) { - - // upload the new texture and create a cl memory - newTexture->uploadTexture(); - cl_mem clNewTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *newTexture); - - // check if opencl memory is unsuccessfull - if(clNewTexture == 0) { - delete newTexture; - return; - } - - // everything seems ok, critical point to replace current texture pointers - _textureLock->lock(); - - // deallocate current texture - clReleaseMemObject(_clTransferFunctions.at(fileID)); - delete _transferFunctions.at(fileID); - - // set the new texture - _transferFunctions.at(fileID) = newTexture; - _clTransferFunctions.at(fileID) = clNewTexture; - - // update kernel - // __kernel arguments(front, back, output, [_volumes], .. fileID)) - _kernel.setArgument(3 + _volumes.size() + fileID, &clNewTexture); - - LDEBUG("Transferfunction successfully updated"); - - // end of critical section - _textureLock->unlock(); - } -} - -} // namespace openspace +// This is still in the repository to be cannibalized for a possible rewrite (ab) +///***************************************************************************************** +// * * +// * OpenSpace * +// * * +// * Copyright (c) 2014 * +// * * +// * Permission is hereby granted, free of charge, to any person obtaining a copy of this * +// * software and associated documentation files (the "Software"), to deal in the Software * +// * without restriction, including without limitation the rights to use, copy, modify, * +// * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * +// * permit persons to whom the Software is furnished to do so, subject to the following * +// * conditions: * +// * * +// * The above copyright notice and this permission notice shall be included in all copies * +// * or substantial portions of the Software. * +// * * +// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * +// * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * +// * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * +// * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * +// * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * +// * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * +// ****************************************************************************************/ +// +//// open space includes +//#include +// +//#include +// +//#include +//#include +//#include +//#include +// +//#include +// +//namespace { +// std::string _loggerCat = "RenderableVolumeExpert"; +// +// size_t countKernelArguments(ghoul::opencl::CLKernel& kernel) { +// +// using ghoul::opencl::CLKernel; +// CLKernel::AddressQualifier adq; +// CLKernel::AccessQualifier acq; +// CLKernel::TypeQualifier atq; +// +// size_t arguments = 0; +// do { +// adq = kernel.argumentAddressQualifier(arguments); +// acq = kernel.argumentAccessQualifier(arguments); +// atq = kernel.argumentTypeQualifier(arguments); +// ++arguments; +// } while (adq != CLKernel::AddressQualifier::Error && +// acq != CLKernel::AccessQualifier::Error && +// atq != CLKernel::TypeQualifier::Error); +// +// return arguments - 1; +// } +//} +// +//namespace openspace { +// +//RenderableVolumeExpert::RenderableVolumeExpert(const ghoul::Dictionary& dictionary): +// RenderableVolume(dictionary), +// _output(nullptr), +// _clBackTexture(0), _clFrontTexture(0), _clOutput(0), +// _kernelSourceFile(nullptr), _programUpdateOnSave(false), _colorBoxRenderer(nullptr), +// _boxScaling(1.0,1.0,1.0) { +// +// _kernelLock = new std::mutex; +// _textureLock = new std::mutex; +// +// if(dictionary.hasKey("Volumes")) { +// ghoul::Dictionary volumes; +// if(dictionary.getValue("Volumes", volumes)) { +// auto keys = volumes.keys(); +// for(auto key: keys) { +// ghoul::Dictionary volume; +// if(volumes.getValue(key, volume)) { +// if (volume.hasKey("File")) { +// std::string file = ""; +// if (volume.getValue("File", file)) { +// file = findPath(file); +// if (file != "") { +// +// // parse hints +// ghoul::Dictionary hintsDictionary; +// if(volume.hasKey("Hints")) +// volume.getValue("Hints", hintsDictionary); +// +// _volumePaths.push_back(file); +// _volumeHints.push_back(hintsDictionary); +// } +// } +// } +// } +// } +// } +// } +// +// if(dictionary.hasKey("TransferFunctions")) { +// ghoul::Dictionary transferFunctions; +// if(dictionary.getValue("TransferFunctions", transferFunctions)) { +// auto keys = transferFunctions.keys(); +// for(auto key: keys) { +// std::string transferFunctionPath = ""; +// if(transferFunctions.getValue(key, transferFunctionPath)) { +// transferFunctionPath = findPath(transferFunctionPath); +// ghoul::opengl::Texture* tmpTexture = loadTransferFunction(transferFunctionPath); +// if(tmpTexture) { +// ghoul::filesystem::File* tmp = new ghoul::filesystem::File(transferFunctionPath, false); +// _transferFunctions.push_back(tmpTexture); +// _transferFunctionsFiles.push_back(tmp); +// } +// } +// } +// } +// } +// +// std::string kernelPath = ""; +// if (dictionary.hasKey("Kernel")) { +// ghoul::Dictionary kernelDictionary; +// if(dictionary.getValue("Kernel", kernelDictionary)) { +// if(kernelDictionary.getValue("Source", kernelPath)) { +// kernelPath = findPath(kernelPath); +// +// } +// if(kernelDictionary.hasKey("UpdateOnSave")) { +// kernelDictionary.getValue("UpdateOnSave", _programUpdateOnSave); +// } +// +// if(kernelDictionary.hasKey("Options")) { +// using namespace ghoul::opencl; +// ghoul::Dictionary kernelOptions; +// if(kernelDictionary.getValue("Options", kernelOptions)) { +// auto keys = kernelOptions.keys(); +// for(auto key: keys) { +// bool value = false; +// if(kernelOptions.getValue(key, value)) { +// if(key == "DenormsAreZero") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::DenormsAreZero, value)); +// } else if(key == "FastRelaxedMath") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::FastRelaxedMath, value)); +// } else if(key == "FiniteMathOnly") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::FiniteMathOnly, value)); +// } else if(key == "KernelArgInfo") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::KernelArgInfo, value)); +// } else if(key == "MadEnable") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::MadEnable, value)); +// } else if(key == "NoSignedZero") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::NoSignedZero, value)); +// } else if(key == "OptDisable") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::OptDisable, value)); +// } else if(key == "SinglePrecisionConstant") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::SinglePrecisionConstant, value)); +// } else if(key == "StrictAliasing") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::StrictAliasing, value)); +// } else if(key == "UnsafeMathOptimizations") { +// _kernelOptions.push_back(std::make_pair(CLProgram::Option::UnsafeMathOptimizations, value)); +// } +// } +// } +// } +// } +// +// ghoul::Dictionary includeDictionary; +// if (kernelDictionary.hasKey("Includes") && kernelDictionary.getValue("Includes", includeDictionary)) { +// auto keys = includeDictionary.keys(); +// for(auto key: keys) { +// std::string includePath; +// if(includeDictionary.getValue(key, includePath)) { +// if(FileSys.directoryExists(includePath)) { +// _kernelIncludes.push_back(absPath(includePath)); +// } +// } +// } +// } +// +// ghoul::Dictionary defineDictionary; +// if (kernelDictionary.hasKey("Definitions") && kernelDictionary.getValue("Definitions", defineDictionary)) { +// auto keys = defineDictionary.keys(); +// for(auto key: keys) { +// std::string defintion; +// if(defineDictionary.getValue(key, defintion)) { +// _kernelDefinitions.push_back(std::make_pair(key, defintion)); +// } +// } +// } +// } +// } +// if (kernelPath != "") { +// _kernelSourceFile = new ghoul::filesystem::File(kernelPath, false); +// } +// +// _colorBoxRenderer = new VolumeRaycasterBox(); +// double tempValue; +// if(dictionary.hasKey("BoxScaling.1") && dictionary.getValue("BoxScaling.1", tempValue)) { +// if(tempValue > 0.0) { +// _boxScaling[0] = tempValue; +// } +// } +// if(dictionary.hasKey("BoxScaling.2") && dictionary.getValue("BoxScaling.2", tempValue)) { +// if(tempValue > 0.0) { +// _boxScaling[1] = tempValue; +// } +// } +// if(dictionary.hasKey("BoxScaling.3") && dictionary.getValue("BoxScaling.3", tempValue)) { +// if(tempValue > 0.0) { +// _boxScaling[2] = tempValue; +// } +// } +// +// setBoundingSphere(PowerScaledScalar::CreatePSS(glm::length(_boxScaling))); +//} +// +//RenderableVolumeExpert::~RenderableVolumeExpert() { +// deinitialize(); +// delete _textureLock; +// delete _kernelLock; +//} +// +//bool RenderableVolumeExpert::initialize() { +// if(_kernelSourceFile == nullptr) { +// LERROR("Could not find the kernel file!"); +// return false; +// } +// +// _context = OsEng.clContext(); +// +// auto textureCallback = [this](const ghoul::filesystem::File& file) { +// safeUpdateTexture(file); +// }; +// auto kernelCallback = [this](const ghoul::filesystem::File& file) { +// safeKernelCompilation(); +// }; +// +// for(auto texture: _transferFunctions) { +// texture->uploadTexture(); +// cl_mem transferMem = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *texture); +// _clTransferFunctions.push_back(transferMem); +// } +// if(_programUpdateOnSave) { +// _kernelSourceFile->setCallback(kernelCallback); +// for(auto texture: _transferFunctionsFiles) { +// texture->setCallback(textureCallback); +// } +// } +// +// for (int i = 0; i < _volumePaths.size(); ++i) { +// ghoul::opengl::Texture* volume = loadVolume(_volumePaths.at(i), _volumeHints.at(i)); +// if(volume) { +// volume->uploadTexture(); +// +// LDEBUG("Creating CL texture from GL texture with path '" << _volumePaths.at(i) << "'"); +// cl_mem volumeTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *volume); +// +// _volumes.push_back(volume); +// _clVolumes.push_back(volumeTexture); +// } else { +// LERROR("Invalid volume"); +// } +// } +// +// // ------ SETUP GEOMETRY ---------------- +// const GLfloat size = 1.0f; +// const GLfloat vertex_texcoord_data[] = { // square of two triangles (sigh) +// // x y z s t +// -size, -size, 0.0f, 0.0f, 0.0f, +// size, size, 0.0f, 1.0f, 1.0f, +// -size, size, 0.0f, 0.0f, 1.0f, +// -size, -size, 0.0f, 0.0f, 0.0f, +// size, -size, 0.0f, 1.0f, 0.0f, +// size, size, 0.0f, 1.0f, 1.0f +// }; +// +// GLuint vertexPositionBuffer; +// glGenVertexArrays(1, &_screenQuad); // generate array +// glBindVertexArray(_screenQuad); // bind array +// glGenBuffers(1, &vertexPositionBuffer); // generate buffer +// glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer +// glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_texcoord_data), vertex_texcoord_data, GL_STATIC_DRAW); +// +// // Vertex positions +// GLuint vertexLocation = 2; +// glEnableVertexAttribArray(vertexLocation); +// glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), reinterpret_cast(0)); +// +// // Texture coordinates +// GLuint texcoordLocation = 0; +// glEnableVertexAttribArray(texcoordLocation); +// glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void*)(3*sizeof(GLfloat))); +// +// glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer +// glBindVertexArray(0); //unbind array +// +// if( ! OsEng.ref().configurationManager().getValue("Quad", _quadProgram)) { +// LERROR("Could not find 'Quad'"); +// return false; +// } +// +// _colorBoxRenderer->initialize(); +// glm::size2_t dimensions = _colorBoxRenderer->dimensions(); +// ghoul::opengl::Texture* backTexture = _colorBoxRenderer->backFace(); +// ghoul::opengl::Texture* frontTexture = _colorBoxRenderer->frontFace(); +// _output = new ghoul::opengl::Texture(glm::size3_t(dimensions[0],dimensions[1],1)); +// _output->uploadTexture(); +// +// _context = OsEng.clContext(); +// _commands = _context.createCommandQueue(); +// +// _clBackTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *backTexture); +// _clFrontTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *frontTexture); +// _clOutput = _context.createTextureFromGLTexture(CL_MEM_WRITE_ONLY, *_output); +// +// // Compile kernels +// safeKernelCompilation(); +// +// // create work group +// size_t local_x = 32; +// size_t local_y = 32; +// while (local_x > 1) { +// if(dimensions[0] % local_x == 0) +// break; +// local_x /= 2; +// } +// while (local_y > 1) { +// if(dimensions[1] % local_y == 0) +// break; +// local_y /= 2; +// } +// _ws = new ghoul::opencl::CLWorkSize({dimensions[0],dimensions[1]}, {local_x,local_y}); +// +// return true; +//} +// +//bool RenderableVolumeExpert::deinitialize() { +// +// +// return true; +//} +// +//void RenderableVolumeExpert::render(const Camera *camera, const psc &thisPosition) { +// if( ! _kernel.isValidKernel()) +// return; +// +// glm::mat4 transform = camera->viewProjectionMatrix(); +// glm::mat4 camTransform = camera->viewRotationMatrix(); +// psc relative = thisPosition-camera->position(); +// +// transform = transform*camTransform; +// transform = glm::translate(transform, relative.vec3()); +// transform = glm::scale(transform, _boxScaling); +// +// _colorBoxRenderer->render(transform); +// +// _textureLock->lock(); +// _kernelLock->lock(); +// +// // tell opengl to finish everything before opencl takes ownerhip (uses) the textures +// glFinish(); +// +// // Aquire GL objects +// _commands.enqueueAcquireGLObjects(_clBackTexture); +// _commands.enqueueAcquireGLObjects(_clFrontTexture); +// _commands.enqueueAcquireGLObjects(_clOutput); +// _commands.enqueueAcquireGLObjects(_clVolumes); +// _commands.enqueueAcquireGLObjects(_clTransferFunctions); +// +// _commands.enqueueKernelBlocking(_kernel, *_ws); +// _commands.finish(); +// +// // Release GL objects +// _commands.enqueueReleaseGLObjects(_clBackTexture); +// _commands.enqueueReleaseGLObjects(_clFrontTexture); +// _commands.enqueueReleaseGLObjects(_clOutput); +// _commands.enqueueReleaseGLObjects(_clVolumes); +// _commands.enqueueReleaseGLObjects(_clTransferFunctions); +// +// _quadProgram->activate(); +// glActiveTexture(GL_TEXTURE0); +// _output->bind(); +// +// // enable blending +// glEnable(GL_BLEND); +// glDisable(GL_DEPTH_TEST); +// glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); +// +// glBindVertexArray(_screenQuad); +// glDrawArrays(GL_TRIANGLES, 0, 6); +// glBindVertexArray(0); +// +// _kernelLock->unlock(); +// _textureLock->unlock(); +// +// // disable blending +// glDisable(GL_BLEND); +// glEnable(GL_DEPTH_TEST); +// glBlendFunc(GL_ONE, GL_ZERO); +// +// _quadProgram->deactivate(); +//} +// +//void RenderableVolumeExpert::update() { +// +//} +// +//void RenderableVolumeExpert::safeKernelCompilation() { +// if(_context.isValidContext()) { +// +// ghoul::opencl::CLProgram tmpProgram = _context.createProgram(_kernelSourceFile->path()); +// for(auto option: _kernelOptions) { +// tmpProgram.setOption(option.first, option.second); +// } +// +// for(auto defintion: _kernelDefinitions) { +// tmpProgram.addDefinition(defintion.first, defintion.second); +// } +// +// // add the include directories +// tmpProgram.addIncludeDirectory(_kernelIncludes); +// +// if(tmpProgram.build()) { +// ghoul::opencl::CLKernel tmpKernel = tmpProgram.createKernel("volumeraycaster"); +// if(tmpKernel.isValidKernel()) { +// +// auto begin = _kernelOptions.begin(); +// auto end = _kernelOptions.end(); +// auto f = std::find(begin, end, std::make_pair(ghoul::opencl::CLProgram::Option::KernelArgInfo, true)); +// +// int maxarguments = 1024; +// bool argumentError = false; +// if (f != end) { +// LDEBUG("Checking argument types"); +// +// using ghoul::opencl::CLKernel; +// maxarguments = countKernelArguments(tmpKernel); +// +// for (int i = 3; i maxarguments) { +// LWARNING("More arguments set than kernel accepts."); +// } +// +// // do the actual assignment behind locked doors +// _kernelLock->lock(); +// _program = tmpProgram; +// _kernel = tmpKernel; +// _kernelLock->unlock(); +// LDEBUG("Done updating kernel"); +// } +// } +// } +//} +// +//void RenderableVolumeExpert::safeUpdateTexture(const ghoul::filesystem::File& file) { +// int fileID = 0; +// for (fileID = 0; fileID < _transferFunctionsFiles.size(); ++fileID) { +// if (_transferFunctionsFiles.at(fileID) == &file) { +// //LDEBUG("Transferfunction found at id " << fileID); +// break; +// } +// } +// if(fileID == _transferFunctionsFiles.size()) +// return; +// +// LDEBUG("Updating transferfunction"); +// +// // create the new texture +// ghoul::opengl::Texture* newTexture = loadTransferFunction(file.path()); +// +// if(newTexture) { +// +// // upload the new texture and create a cl memory +// newTexture->uploadTexture(); +// cl_mem clNewTexture = _context.createTextureFromGLTexture(CL_MEM_READ_ONLY, *newTexture); +// +// // check if opencl memory is unsuccessfull +// if(clNewTexture == 0) { +// delete newTexture; +// return; +// } +// +// // everything seems ok, critical point to replace current texture pointers +// _textureLock->lock(); +// +// // deallocate current texture +// clReleaseMemObject(_clTransferFunctions.at(fileID)); +// delete _transferFunctions.at(fileID); +// +// // set the new texture +// _transferFunctions.at(fileID) = newTexture; +// _clTransferFunctions.at(fileID) = clNewTexture; +// +// // update kernel +// // __kernel arguments(front, back, output, [_volumes], .. fileID)) +// _kernel.setArgument(3 + _volumes.size() + fileID, &clNewTexture); +// +// LDEBUG("Transferfunction successfully updated"); +// +// // end of critical section +// _textureLock->unlock(); +// } +//} +// +//} // namespace openspace diff --git a/src/rendering/renderablevolumegl.cpp b/src/rendering/renderablevolumegl.cpp index 0d1ae60475..232b443b18 100644 --- a/src/rendering/renderablevolumegl.cpp +++ b/src/rendering/renderablevolumegl.cpp @@ -22,262 +22,270 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -// open space includes #include - #include +#include +#include #include #include #include -#include - #include +#include +#include + namespace { - std::string _loggerCat = "RenderableVolumeGL"; + const std::string _loggerCat = "RenderableVolumeGL"; } namespace openspace { -RenderableVolumeGL::RenderableVolumeGL(const ghoul::Dictionary& dictionary): - RenderableVolume(dictionary), - _backTexture(nullptr), _frontTexture(nullptr), _screenQuad(0), - _programUpdateOnSave(false) { - - _shaderMutex = new std::mutex; +RenderableVolumeGL::RenderableVolumeGL(const ghoul::Dictionary& dictionary) + : RenderableVolume(dictionary) + , _transferFunctionName("") + , _volumeName("") + , _boxScaling(1.0, 1.0, 1.0) + , _w(0.f) + , _updateTransferfunction(false) + , _id(-1) +{ + std::string name; + bool success = dictionary.getValue(constants::scenegraphnode::keyName, name); + assert(success); _filename = ""; - if(dictionary.hasKey("Volume")) { - if(dictionary.getValue("Volume", _filename)) { - _filename = findPath(_filename); - } - } - - LDEBUG("filename: " << _filename); - - ghoul::Dictionary hintsDictionary; - if(dictionary.hasKey("Hints")) - dictionary.getValue("Hints", hintsDictionary); - _hints = readHints(hintsDictionary); + success = dictionary.getValueSafe(constants::renderablevolumegl::keyVolume, + _filename); + if (!success) { + LERROR("Node '" << name << "' did not contain a valid '" << + constants::renderablevolumegl::keyVolume << "'"); + return; + } + _filename = findPath(_filename); - std::string vshaderpath = ""; - std::string fshaderpath = ""; - - if (dictionary.hasKey("Shaders")) { - ghoul::Dictionary shaderDictionary; - if(dictionary.getValue("Shaders", shaderDictionary)) { - if (shaderDictionary.hasKey("VertexShader")) { - shaderDictionary.getValue("VertexShader", vshaderpath); - } - if (shaderDictionary.hasKey("FragmentShader")) { - shaderDictionary.getValue("FragmentShader", fshaderpath); - } - - vshaderpath = findPath(vshaderpath); - fshaderpath = findPath(fshaderpath); - - _vertexSourceFile = new ghoul::filesystem::File(vshaderpath, false); - _fragmentSourceFile = new ghoul::filesystem::File(fshaderpath, false); - - _twopassProgram = new ghoul::opengl::ProgramObject("TwoPassProgram"); - ghoul::opengl::ShaderObject* vertexShader = new ghoul::opengl::ShaderObject(ghoul::opengl::ShaderObject::ShaderTypeVertex,vshaderpath); - ghoul::opengl::ShaderObject* fragmentShader = new ghoul::opengl::ShaderObject(ghoul::opengl::ShaderObject::ShaderTypeFragment,fshaderpath); - _twopassProgram->attachObject(vertexShader); - _twopassProgram->attachObject(fragmentShader); - } - - - } - - if(dictionary.hasKey("UpdateOnSave")) { - dictionary.getValue("UpdateOnSave", _programUpdateOnSave); - } + LDEBUG("Volume Filename: " << _filename); + dictionary.getValueSafe(constants::renderablevolumegl::keyHints, _hintsDictionary); + + _transferFunction = nullptr; + _transferFunctionFile = nullptr; + _transferFunctionPath = ""; + success = dictionary.getValueSafe( + constants::renderablevolumegl::keyTransferFunction, _transferFunctionPath); + if (!success) { + LERROR("Node '" << name << "' did not contain a valid '" << + constants::renderablevolumegl::keyTransferFunction << "'"); + return; + } + _transferFunctionPath = findPath(_transferFunctionPath); + _transferFunctionFile = new ghoul::filesystem::File(_transferFunctionPath, true); + + _samplerFilename = ""; + success = dictionary.getValueSafe(constants::renderablevolumegl::keySampler, + _samplerFilename); + if (!success) { + LERROR("Node '" << name << "' did not contain a valid '" << + constants::renderablevolumegl::keySampler << "'"); + return; + } + _samplerFilename = findPath(_samplerFilename); + + glm::vec4 scalingVec4(_boxScaling, _w); + success = dictionary.getValueSafe(constants::renderablevolumegl::keyBoxScaling, + scalingVec4); + if (success) { + _boxScaling = scalingVec4.xyz; + _w = scalingVec4.w; + } + else { + success = dictionary.getValueSafe(constants::renderablevolumegl::keyBoxScaling, + _boxScaling); + if (!success) { + LERROR("Node '" << name << "' did not contain a valid '" << + constants::renderablevolumegl::keyBoxScaling << "'"); + return; + } + } + + dictionary.getValueSafe(constants::renderablevolumegl::keyVolumeName, _volumeName); + dictionary.getValueSafe(constants::renderablevolumegl::keyTransferFunctionName, + _transferFunctionName); + + setBoundingSphere(PowerScaledScalar::CreatePSS(glm::length(_boxScaling)*pow(10,_w))); } RenderableVolumeGL::~RenderableVolumeGL() { deinitialize(); - if(_fbo) - delete _fbo; - if(_backTexture) - delete _backTexture; - if(_frontTexture) - delete _frontTexture; if(_volume) delete _volume; - if(_boundingBox) - delete _boundingBox; + if(_transferFunctionFile) + delete _transferFunctionFile; + if(_transferFunction) + delete _transferFunction; } bool RenderableVolumeGL::initialize() { - assert(_filename != ""); + // assert(_filename != ""); // ------ VOLUME READING ---------------- - ghoul::RawVolumeReader rawReader(_hints); - _volume = rawReader.read(_filename); - - // ------ SETUP GEOMETRY ---------------- - const GLfloat size = 1.0f; - const GLfloat vertex_texcoord_data[] = { // square of two triangles (sigh) - // x y z s t - -size, -size, 0.0f, 0.0f, 0.0f, - size, size, 0.0f, 1.0f, 1.0f, - -size, size, 0.0f, 0.0f, 1.0f, - -size, -size, 0.0f, 0.0f, 0.0f, - size, -size, 0.0f, 1.0f, 0.0f, - size, size, 0.0f, 1.0f, 1.0f - }; - - GLuint vertexPositionBuffer; - glGenVertexArrays(1, &_screenQuad); // generate array - glBindVertexArray(_screenQuad); // bind array - glGenBuffers(1, &vertexPositionBuffer); // generate buffer - glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_texcoord_data), vertex_texcoord_data, GL_STATIC_DRAW); - - // Vertex positions - GLuint vertexLocation = 2; - glEnableVertexAttribArray(vertexLocation); - glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), reinterpret_cast(0)); - - // Texture coordinates - GLuint texcoordLocation = 0; - glEnableVertexAttribArray(texcoordLocation); - glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (void*)(3*sizeof(GLfloat))); - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind buffer - glBindVertexArray(0); //unbind array - - _boundingBox = new sgct_utils::SGCTBox(1.0f, sgct_utils::SGCTBox::Regular); - - // ------ SETUP SHADERS ----------------- - // TODO error control or better design pattern - OsEng.ref().configurationManager().getValue("RaycastProgram", _fboProgram); - - auto privateCallback = [this](const ghoul::filesystem::File& file) { - safeShaderCompilation(); - }; - if(_programUpdateOnSave) { - _vertexSourceFile->setCallback(privateCallback); - _fragmentSourceFile->setCallback(privateCallback); - } - - _twopassProgram->compileShaderObjects(); - _twopassProgram->linkProgramObject(); - _twopassProgram->setUniform("texBack", 0); - _twopassProgram->setUniform("texFront", 1); - _twopassProgram->setUniform("texVolume", 2); - //OsEng.ref().configurationManager().getValue("TwoPassProgram", _twopassProgram); - - // ------ SETUP FBO --------------------- - _fbo = new ghoul::opengl::FramebufferObject(); - _fbo->activate(); - - int x = sgct::Engine::instance()->getActiveXResolution(); - int y = sgct::Engine::instance()->getActiveYResolution(); - _backTexture = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); - _frontTexture = new ghoul::opengl::Texture(glm::size3_t(x,y,1)); - _backTexture->uploadTexture(); - _frontTexture->uploadTexture(); - _fbo->attachTexture(_backTexture, GL_COLOR_ATTACHMENT0); - _fbo->attachTexture(_frontTexture, GL_COLOR_ATTACHMENT1); - - _fbo->deactivate(); +// <<<<<<< HEAD +// ======= +// _volume = loadVolume(_filename, _hintsDictionary); +// _volume->uploadTexture(); +// _transferFunction = loadTransferFunction(_transferFunctionPath); +// _transferFunction->uploadTexture(); +// >>>>>>> feature/fieldlines + // TODO: fix volume an transferfunction names + if(_filename != "") { + _volume = loadVolume(_filename, _hintsDictionary); + _boxOffset = getVolumeOffset(_filename, _hintsDictionary); + _volume->uploadTexture(); + OsEng.renderEngine().abuffer()->addVolume(_volumeName, _volume); + } + + if(_transferFunctionPath != "") { + _transferFunction = loadTransferFunction(_transferFunctionPath); + _transferFunction->uploadTexture(); + OsEng.renderEngine().abuffer()->addTransferFunction(_transferFunctionName, _transferFunction); + + auto textureCallback = [this](const ghoul::filesystem::File& file) { + _updateTransferfunction = true; + }; + _transferFunctionFile->setCallback(textureCallback); + } + + // add the sampler and get the ID + _id = OsEng.renderEngine().abuffer()->addSamplerfile(_samplerFilename); + + OsEng.configurationManager().getValue("RaycastProgram", _boxProgram); + _MVPLocation = _boxProgram->uniformLocation("modelViewProjection"); + _modelTransformLocation = _boxProgram->uniformLocation("modelTransform"); + _typeLocation = _boxProgram->uniformLocation("volumeType"); + + // ============================ + // GEOMETRY (quad) + // ============================ + const GLfloat size = 0.5f; + const GLfloat vertex_data[] = { // square of two triangles (sigh) + // x, y, z, s, + -size, -size, size, _w, + size, size, size, _w, + -size, size, size, _w, + -size, -size, size, _w, + size, -size, size, _w, + size, size, size, _w, + + -size, -size, -size, _w, + size, size, -size, _w, + -size, size, -size, _w, + -size, -size, -size, _w, + size, -size, -size, _w, + size, size, -size, _w, + + size, -size, -size, _w, + size, size, size, _w, + size, -size, size, _w, + size, -size, -size, _w, + size, size, -size, _w, + size, size, size, _w, + + -size, -size, -size, _w, + -size, size, size, _w, + -size, -size, size, _w, + -size, -size, -size, _w, + -size, size, -size, _w, + -size, size, size, _w, + + -size, size, -size, _w, + size, size, size, _w, + -size, size, size, _w, + -size, size, -size, _w, + size, size, -size, _w, + size, size, size, _w, + + -size, -size, -size, _w, + size, -size, size, _w, + -size, -size, size, _w, + -size, -size, -size, _w, + size, -size, -size, _w, + size, -size, size, _w, + }; + GLuint vertexPositionBuffer; + glGenVertexArrays(1, &_boxArray); // generate array + glBindVertexArray(_boxArray); // bind array + glGenBuffers(1, &vertexPositionBuffer); // generate buffer + glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer); // bind buffer + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*4, reinterpret_cast(0)); + glEnableVertexAttribArray(0); return true; } bool RenderableVolumeGL::deinitialize() { - - return true; } void RenderableVolumeGL::render(const Camera *camera, const psc &thisPosition) { - - float speed = 50.0f; - float time = sgct::Engine::getTime(); - glm::mat4 transform = camera->viewProjectionMatrix(); - - double factor = pow(10.0,thisPosition[3]); - transform = glm::translate(transform, glm::vec3(thisPosition[0]*factor, thisPosition[1]*factor, thisPosition[2]*factor)); - transform = glm::rotate(transform, time*speed, glm::vec3(0.0f, 1.0f, 0.0f)); - - - _stepSize = 0.01f; - - // ------ DRAW TO FBO ------------------- - GLuint sgctFBO = ghoul::opengl::FramebufferObject::getActiveObject(); // Save SGCTs main FBO - _fbo->activate(); - _fboProgram->activate(); - _fboProgram->setUniform("modelViewProjection", transform); - - // Draw backface - glDrawBuffer(GL_COLOR_ATTACHMENT0); - glClearColor(0.2f, 0.2f, 0.2f, 0); - glClear(GL_COLOR_BUFFER_BIT); - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - _boundingBox->draw(); - glDisable(GL_CULL_FACE); - - // Draw frontface - glDrawBuffer(GL_COLOR_ATTACHMENT1); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.2f, 0.2f, 0.2f, 0); - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - _boundingBox->draw(); - glDisable(GL_CULL_FACE); - - _fboProgram->deactivate(); - _fbo->deactivate(); - - // ------ DRAW TO SCREEN ---------------- - glBindFramebuffer(GL_FRAMEBUFFER, sgctFBO); // Re-bind SGCTs main FBO - - // Draw screenquad - glClearColor(0.2f, 0.2f, 0.2f, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - _shaderMutex->lock(); - _twopassProgram->activate(); - _twopassProgram->setUniform("stepSize", _stepSize); - - // Set textures - glActiveTexture(GL_TEXTURE0); - _backTexture->bind(); - glActiveTexture(GL_TEXTURE1); - _frontTexture->bind(); - glActiveTexture(GL_TEXTURE2); - _volume->bind(); - - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - - _twopassProgram->deactivate(); - _shaderMutex->unlock(); + if(_updateTransferfunction) { + _updateTransferfunction = false; + ghoul::opengl::Texture* transferFunction = loadTransferFunction(_transferFunctionPath); + if(transferFunction) { + const void* data = transferFunction->pixelData(); + glBindBuffer(GL_COPY_READ_BUFFER, *transferFunction); + _transferFunction->bind(); + glTexImage1D( GL_TEXTURE_1D, 0, _transferFunction->internalFormat(), + _transferFunction->width(),0, _transferFunction->format(), + _transferFunction->dataType(), data); + delete transferFunction; + LDEBUG("Updated transferfunction!"); + } + } + + glm::mat4 transform = glm::mat4(1.0); + transform = glm::scale(transform, _boxScaling); + + // fetch data + psc currentPosition = thisPosition; + psc campos = camera->position(); + glm::mat4 camrot = camera->viewRotationMatrix(); + PowerScaledScalar scaling = camera->scaling(); + + // psc addon(-1.1,0.0,0.0,0.0); + // currentPosition += addon; + psc addon(_boxOffset/100.0f); // TODO: Proper scaling/units + currentPosition += addon; // Move box to model barycenter + + // TODO: Use _id to identify this volume + _boxProgram->activate(); + _boxProgram->setUniform(_typeLocation, _id); + + _boxProgram->setUniform("modelViewProjection", camera->viewProjectionMatrix()); + _boxProgram->setUniform("modelTransform", transform); + _boxProgram->setUniform("campos", campos.vec4()); + _boxProgram->setUniform("objpos", currentPosition.vec4()); + _boxProgram->setUniform("camrot", camrot); + _boxProgram->setUniform("scaling", scaling.vec2()); + + // make sure GL_CULL_FACE is enabled (it should be) + glEnable(GL_CULL_FACE); + + // Draw backface + glCullFace(GL_FRONT); + glBindVertexArray(_boxArray); + glDrawArrays(GL_TRIANGLES, 0, 6*6); + + // Draw frontface (now the normal cull face is is set) + glCullFace(GL_BACK); + glDrawArrays(GL_TRIANGLES, 0, 6*6); + + _boxProgram->deactivate(); } void RenderableVolumeGL::update() { - } -void RenderableVolumeGL::safeShaderCompilation() { - _shaderMutex->lock(); - _twopassProgram->rebuildFromFile(); - _twopassProgram->compileShaderObjects(); - _twopassProgram->linkProgramObject(); - _twopassProgram->setUniform("texBack", 0); - _twopassProgram->setUniform("texFront", 1); - _twopassProgram->setUniform("texVolume", 2); - _shaderMutex->unlock(); -} - - - -} // namespace openspace \ No newline at end of file +} // namespace openspace diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index bab4a7ac2d..cb371db858 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "sgct.h" @@ -34,6 +35,10 @@ #include +#include +#include +#include + namespace { const std::string _loggerCat = "RenderEngine"; } @@ -42,6 +47,7 @@ namespace openspace { RenderEngine::RenderEngine() : _mainCamera(nullptr) , _sceneGraph(nullptr) + , _abuffer(nullptr) { } @@ -52,20 +58,29 @@ RenderEngine::~RenderEngine() bool RenderEngine::initialize() { + // LDEBUG("RenderEngine::initialize()"); // init camera and set temporary position and scaling _mainCamera = new Camera(); _mainCamera->setScaling(glm::vec2(1.0, -8.0)); - _mainCamera->setPosition(psc(0.0, 0.0, 1.499823, 11.0)); + _mainCamera->setPosition(psc(0.f, 0.f, 1.499823f, 11.f)); // if master, setup interaction //if (sgct::Engine::instance()->isMaster()) OsEng.interactionHandler().setCamera(_mainCamera); +#if ABUFFER_IMPLEMENTATION == ABUFFER_SINGLE_LINKED + _abuffer = new ABufferSingleLinked(); +#elif ABUFFER_IMPLEMENTATION == ABUFFER_FIXED + _abuffer = new ABufferFixed(); +#elif ABUFFER_IMPLEMENTATION == ABUFFER_DYNAMIC + _abuffer = new ABufferDynamic(); +#endif return true; } bool RenderEngine::initializeGL() { + // LDEBUG("RenderEngine::initializeGL()"); sgct::SGCTWindow* wPtr = sgct::Engine::instance()->getActiveWindowPtr(); // TODO: Fix the power scaled coordinates in such a way that these values can be @@ -76,6 +91,7 @@ bool RenderEngine::initializeGL() // development // sgct::Engine::instance()->setNearAndFarClippingPlanes(0.1f,100.0f); sgct::Engine::instance()->setNearAndFarClippingPlanes(0.0001f, 100.0f); + sgct::Engine::instance()->setNearAndFarClippingPlanes(0.1f, 200.0f); // calculating the maximum field of view for the camera, used to // determine visibility of objects in the scene graph @@ -133,6 +149,8 @@ bool RenderEngine::initializeGL() _mainCamera->setMaxFov(maxFov); } + _abuffer->initialize(); + // successful init return true; } @@ -152,8 +170,10 @@ void RenderEngine::postSynchronizationPreDraw() void RenderEngine::render() { // SGCT resets certain settings - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); + //glEnable(GL_DEPTH_TEST); + //glEnable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); // setup the camera for the current frame const glm::vec3 eyePosition @@ -175,8 +195,13 @@ void RenderEngine::render() // render the scene starting from the root node + _abuffer->clear(); + _abuffer->preRender(); _sceneGraph->render(_mainCamera); + _abuffer->postRender(); + _abuffer->resolve(); +#ifndef OPENSPACE_VIDEO_EXPORT // Print some useful information on the master viewport if (sgct::Engine::instance()->isMaster()) { // Apple usually has retina screens @@ -192,6 +217,23 @@ void RenderEngine::render() const psc origin = OsEng.interactionHandler().getOrigin(); const PowerScaledScalar pssl = (position - origin).length(); + const std::string time = Time::ref().currentTimeUTC().c_str(); + Freetype::print( + sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), + FONT_SIZE, FONT_SIZE * 18, "Date: %s", time.c_str() + ); + Freetype::print( + sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), + FONT_SIZE, FONT_SIZE * 16, "Avg. Frametime: %.10f", sgct::Engine::instance()->getAvgDt() + ); + Freetype::print( + sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), + FONT_SIZE, FONT_SIZE * 14, "Drawtime: %.10f", sgct::Engine::instance()->getDrawTime() + ); + Freetype::print( + sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), + FONT_SIZE, FONT_SIZE * 12, "Frametime: %.10f", sgct::Engine::instance()->getDt() + ); Freetype::print( sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), FONT_SIZE, FONT_SIZE * 10, "Origin: (%.5f, %.5f, %.5f, %.5f)", origin[0], @@ -211,7 +253,10 @@ void RenderEngine::render() Freetype::print( sgct_text::FontManager::instance()->getFont("SGCTFont", FONT_SIZE), FONT_SIZE, FONT_SIZE * 2, "Scaling: (%.10f, %.2f)", scaling[0], scaling[1]); + } +#endif + } SceneGraph* RenderEngine::sceneGraph() @@ -401,4 +446,8 @@ Camera* RenderEngine::camera() const { return _mainCamera; } +ABuffer* RenderEngine::abuffer() const { + return _abuffer; +} + } // namespace openspace diff --git a/src/rendering/stars/renderablestars.cpp b/src/rendering/stars/renderablestars.cpp index e3f4ee6c41..379bcf5e9c 100644 --- a/src/rendering/stars/renderablestars.cpp +++ b/src/rendering/stars/renderablestars.cpp @@ -395,6 +395,7 @@ void RenderableStars::render(const Camera* camera, const psc& thisPosition){ _haloProgram->deactivate(); #ifdef GLPOINTS + /* // ---------------------- RENDER POINTS ----------------------------- _pointProgram->activate(); @@ -415,7 +416,7 @@ void RenderableStars::render(const Camera* camera, const psc& thisPosition){ glDisable(GL_BLEND); _pointProgram->deactivate(); - + */ #endif } diff --git a/src/rendering/volumeraycasterbox.cpp b/src/rendering/volumeraycasterbox.cpp index 3e27e0d95d..4fb33a1bde 100644 --- a/src/rendering/volumeraycasterbox.cpp +++ b/src/rendering/volumeraycasterbox.cpp @@ -61,7 +61,9 @@ bool VolumeRaycasterBox::initialize() { // ------ SETUP SHADER ----------------- OsEng.configurationManager().getValue("RaycastProgram", _boxProgram); - _MVPLocation = _boxProgram->uniformLocation("modelViewProjection"); + _MVPLocation = _boxProgram->uniformLocation("modelViewProjection"); + _modelTransformLocation = _boxProgram->uniformLocation("modelTransform"); + _typeLocation = _boxProgram->uniformLocation("volumeType"); // ------ SETUP FBO --------------------- _fbo = new FramebufferObject(); @@ -69,8 +71,6 @@ bool VolumeRaycasterBox::initialize() { // changed from getActiveXResolution to getCurrentViewportPixelCoords because // if there are more viewports in the same screen. - //size_t x = sgct::Engine::instance()->getActiveXResolution(); - //size_t y = sgct::Engine::instance()->getActiveYResolution(); int x1, xSize, y1, ySize; sgct::Engine::instance()->getActiveWindowPtr()->getCurrentViewportPixelCoords(x1, y1, xSize, ySize); size_t x = xSize; @@ -89,11 +89,13 @@ bool VolumeRaycasterBox::initialize() { return true; } -void VolumeRaycasterBox::render(const glm::mat4& MVP) { +void VolumeRaycasterBox::render(const glm::mat4& MVP,const glm::mat4& transform, int type) { GLuint activeFBO = FramebufferObject::getActiveObject(); // Save SGCTs main FBO _fbo->activate(); _boxProgram->activate(); - _boxProgram->setUniform(_MVPLocation, MVP); + _boxProgram->setUniform(_MVPLocation, MVP); + _boxProgram->setUniform(_modelTransformLocation, transform); + _boxProgram->setUniform(_typeLocation, type); sgct_core::Frustum::FrustumMode mode = sgct::Engine::instance()-> getActiveWindowPtr()-> diff --git a/src/scenegraph/ephemeris.cpp b/src/scenegraph/ephemeris.cpp index dc7e2a5833..ae2d5080d8 100644 --- a/src/scenegraph/ephemeris.cpp +++ b/src/scenegraph/ephemeris.cpp @@ -55,11 +55,19 @@ Ephemeris* Ephemeris::createFromDictionary(const ghoul::Dictionary& dictionary) Ephemeris::Ephemeris() { } + Ephemeris::Ephemeris(const ghoul::Dictionary& dictionary) { } + Ephemeris::~Ephemeris() { } + +bool Ephemeris::initialize() { + return true; +} + +void Ephemeris::update() {} } // namespace openspace \ No newline at end of file diff --git a/src/scenegraph/scenegraph.cpp b/src/scenegraph/scenegraph.cpp index decde3bf90..a9dcfc6d54 100644 --- a/src/scenegraph/scenegraph.cpp +++ b/src/scenegraph/scenegraph.cpp @@ -24,11 +24,14 @@ // open space includes #include -#include -#include -#include #include +#include +#include +#include +#include #include +#include +#include // ghoul includes #include "ghoul/opengl/programobject.h" @@ -46,26 +49,135 @@ #include #include -namespace { -const std::string _loggerCat = "SceneGraph"; -const std::string _rootNodeName = "Root"; -const std::string _moduleExtension = ".mod"; +#include + //#include +namespace { + const std::string _loggerCat = "SceneGraph"; + const std::string _moduleExtension = ".mod"; } namespace openspace { -void printTree(SceneGraphNode* node, std::string pre = "") -{ - LDEBUGC("Tree", pre << node->nodeName()); - const std::vector& children = node->children(); - for (SceneGraphNode* child : children) - printTree(child, pre + " "); +namespace luascriptfunctions { + +/** + * \ingroup LuaScripts + * setPropertyValue(string, *): + * Sets the property identified by the URI in the first argument to the value passed to + * the second argument. The type of the second argument is arbitrary, but it must agree + * with the type the denoted Property expects + */ +int property_setValue(lua_State* L) { + using ghoul::lua::luaTypeToString; + const std::string _loggerCat = "property_setValue"; + + // TODO Check for argument number (ab) + std::string uri = luaL_checkstring(L, -2); + const int type = lua_type(L, -1); + // boost::any propertyValue; + // switch (type) { + // case LUA_TNONE: + // case LUA_TLIGHTUSERDATA: + // case LUA_TFUNCTION: + // case LUA_TUSERDATA: + // case LUA_TTHREAD: + // LERROR("Function parameter was of type '" << luaTypeToString(type) << "'"); + // return 0; + // case LUA_TNIL: + // propertyValue = 0; + // break; + // case LUA_TBOOLEAN: + // propertyValue = lua_toboolean(L, -1); + // break; + // case LUA_TNUMBER: + // propertyValue = lua_tonumber(L, -1); + // break; + // case LUA_TSTRING: + // propertyValue = std::string(lua_tostring(L, -1)); + // break; + //case LUA_TTABLE: { + // ghoul::Dictionary d; + // ghoul::lua::populateDictionary(L, d); + // propertyValue = d; + // break; + //} + // } + + openspace::properties::Property* prop = property(uri); + if (!prop) { + LERROR("Property with uri '" << uri << "' could not be found"); + return 0; + } + + if (type != prop->typeLua()) + LERROR("Property '" << uri << "' does not accept input of type '" + << luaTypeToString(type) << "'. Requested type: '" + << luaTypeToString(prop->typeLua()) << "'"); + else + prop->setLua(L); + //prop->set(propertyValue); + + return 0; } +/** + * \ingroup LuaScripts + * getPropertyValue(string): + * Returns the value of the property identified by the passed URI as a Lua object that can + * be passed to the setPropertyValue method. + */ +int property_getValue(lua_State* L) { + const std::string _loggerCat = "property_getValue"; + + // TODO Check for argument number (ab) + std::string uri = luaL_checkstring(L, -1); + + openspace::properties::Property* prop = property(uri); + if (!prop) { + LERROR("Property with uri '" << uri << "' could not be found"); + lua_pushnil(L); + } + else { + prop->getLua(L); + + //switch (type) { + // case LUA_TNONE: + // case LUA_TLIGHTUSERDATA: + // case LUA_TFUNCTION: + // case LUA_TUSERDATA: + // case LUA_TTHREAD: + // LERROR("Function parameter was of type '" << luaTypeToString(type) + // << "'"); + // return 0; + // case LUA_TNIL: + // propertyValue = 0; + // break; + // case LUA_TBOOLEAN: + // propertyValue = lua_toboolean(L, -1); + // break; + // case LUA_TNUMBER: + // propertyValue = lua_tonumber(L, -1); + // break; + // case LUA_TSTRING: + // propertyValue = std::string(lua_tostring(L, -1)); + // break; + // case LUA_TTABLE: { + // ghoul::Dictionary d; + // ghoul::lua::populateDictionary(L, d); + // propertyValue = d; + // break; + // } + //} + } + return 1; +} + +} // namespace luascriptfunctions + SceneGraph::SceneGraph() - : _focus("Root") - , _position("Root") + : _focus(SceneGraphNode::RootNodeName) + , _position(SceneGraphNode::RootNodeName) , _root(nullptr) { } @@ -78,16 +190,97 @@ SceneGraph::~SceneGraph() bool SceneGraph::initialize() { LDEBUG("Initializing SceneGraph"); - + + LDEBUG("Creating ProgramObjects"); using ghoul::opengl::ShaderObject; using ghoul::opengl::ProgramObject; - ProgramObject* po = nullptr; - if (OsEng.ref().configurationManager().hasKey("pscShader") - && OsEng.ref().configurationManager().getValue("pscShader", po)) { - LWARNING("pscShader already in ConfigurationManager, deleting."); + ShaderCreator sc = OsEng.shaderBuilder(); + ProgramObject* tmpProgram; + + typedef std::chrono::high_resolution_clock clock_; + typedef std::chrono::duration > second_; + + std::chrono::time_point beg_(clock_::now()); + + + // pscstandard + tmpProgram = sc.buildShader("pscstandard", + "${SHADERS}/pscstandard_vs.glsl", + "${SHADERS}/pscstandard_fs.glsl"); + if( ! tmpProgram) return false; + OsEng.ref().configurationManager().setValue("pscShader", tmpProgram); + + // RaycastProgram + tmpProgram = sc.buildShader("RaycastProgram", + "${SHADERS}/exitpoints.vert", + "${SHADERS}/exitpoints.frag"); + if( ! tmpProgram) return false; + OsEng.ref().configurationManager().setValue("RaycastProgram", tmpProgram); + + + // // TwoPassProgram + // tmpProgram = sc.buildShader("TwoPassProgram", + // "${SHADERS}/twopassraycaster.vert", + // "${SHADERS}/twopassraycaster.frag"); + // if( ! tmpProgram) return false; + // tmpProgram->setUniform("texBack", 0); + // tmpProgram->setUniform("texFront", 1); + // tmpProgram->setUniform("texVolume", 2); + // OsEng.ref().configurationManager().setValue("TwoPassProgram", tmpProgram); + + // Quad + tmpProgram = sc.buildShader("Quad", + "${SHADERS}/quadVert.glsl", + "${SHADERS}/quadFrag.glsl"); + if (!tmpProgram) return false; + tmpProgram->setUniform("quadTex", 0); + OsEng.ref().configurationManager().setValue("Quad", tmpProgram); + + // Star program + tmpProgram = sc.buildShader("Star", + "${SHADERS}/star_vs.glsl", + "${SHADERS}/star_fs.glsl", + "${SHADERS}/star_ge.glsl"); + if (!tmpProgram) return false; + OsEng.ref().configurationManager().setValue("StarProgram", tmpProgram); + + // Point program + tmpProgram = sc.buildShader("Point", + "${SHADERS}/star_vs.glsl", + "${SHADERS}/star_fs.glsl", + "${SHADERS}/star_ge.glsl"); + if (!tmpProgram) return false; + OsEng.ref().configurationManager().setValue("PointProgram", tmpProgram); + + + + double elapsed = std::chrono::duration_cast(clock_::now() - beg_).count(); + LERROR("Time to load shaders: " << elapsed); + + /* + + auto programCreator = [] ( const std::string& name, + const std::string& vpath, + const std::string& fpath) + { + const std::string vsPath = absPath(vpath); + const std::string fsPath = absPath(fpath); + const ShaderObject::ShaderType vsType = ShaderObject::ShaderType::ShaderTypeVertex; + const ShaderObject::ShaderType fsType = ShaderObject::ShaderType::ShaderTypeFragment; + + ProgramObject* po = new ProgramObject(name); + ShaderObject* vs = new ShaderObject(vsType, vsPath, name + "Vertex"); + ShaderObject* fs = new ShaderObject(fsType, fsPath, name + "Fragment"); + po->attachObject(vs); + po->attachObject(fs); + if ( po->compileShaderObjects() && po->linkProgramObject()) + return po; + + // unsuccessful compilation, cleanup and return nullptr delete po; po = nullptr; +//<<<<<<< HEAD } ShaderObject* powerscale_vs @@ -178,14 +371,51 @@ bool SceneGraph::initialize() OsEng.ref().configurationManager().setValue("StarProgram", _starProgram); +======= + return po; + }; + // pscstandard + tmpProgram = programCreator("pscstandard", + "${SHADERS}/pscstandard_vs.glsl", + "${SHADERS}/pscstandard_fs.glsl"); + if( ! tmpProgram) return false; + OsEng.ref().configurationManager().setValue("pscShader", tmpProgram); + + // RaycastProgram + tmpProgram = programCreator("RaycastProgram", + "${SHADERS}/exitpoints.vert", + "${SHADERS}/exitpoints.frag"); + if( ! tmpProgram) return false; + OsEng.ref().configurationManager().setValue("RaycastProgram", tmpProgram); + + + // TwoPassProgram + tmpProgram = programCreator("TwoPassProgram", + "${SHADERS}/twopassraycaster.vert", + "${SHADERS}/twopassraycaster.frag"); + if( ! tmpProgram) return false; + tmpProgram->setUniform("texBack", 0); + tmpProgram->setUniform("texFront", 1); + tmpProgram->setUniform("texVolume", 2); + OsEng.ref().configurationManager().setValue("TwoPassProgram", tmpProgram); + + // Quad + tmpProgram = programCreator("Quad", + "${SHADERS}/quadVert.glsl", + "${SHADERS}/quadFrag.glsl"); + if( ! tmpProgram) return false; + tmpProgram->setUniform("quadTex", 0); + OsEng.ref().configurationManager().setValue("Quad", tmpProgram); + */ +//>>>>>>> develop // Initialize all nodes for (auto node : _nodes) { bool success = node->initialize(); if (success) - LDEBUG(node->nodeName() << " initialized successfully!"); + LDEBUG(node->name() << " initialized successfully!"); else - LWARNING(node->nodeName() << " not initialized."); + LWARNING(node->name() << " not initialized."); } // update the position of all nodes @@ -217,7 +447,7 @@ bool SceneGraph::initialize() glm::vec2 scaling{1.0f, -boundf[1]}; boundf[0] *= 5.0f; - psc cameraPosition = positionNode->getPosition(); + psc cameraPosition = positionNode->position(); cameraPosition += psc(glm::vec4(0.f, 0.f, boundf)); c->setPosition(cameraPosition); @@ -240,8 +470,8 @@ bool SceneGraph::deinitialize() _nodes.erase(_nodes.begin(), _nodes.end()); _allNodes.erase(_allNodes.begin(), _allNodes.end()); - _focus = ""; - _position = ""; + _focus.clear(); + _position.clear(); return true; } @@ -277,9 +507,9 @@ bool SceneGraph::loadScene(const std::string& sceneDescriptionFilePath, // initialize the root node _root = new SceneGraphNode(); - _root->setName(_rootNodeName); + _root->setName(SceneGraphNode::RootNodeName); _nodes.push_back(_root); - _allNodes.emplace(_rootNodeName, _root); + _allNodes.emplace(SceneGraphNode::RootNodeName, _root); Dictionary dictionary; //load default.scene @@ -356,12 +586,12 @@ void SceneGraph::loadModule(const std::string& modulePath) //each element in this new dictionary becomes a scenegraph node. SceneGraphNode* node = SceneGraphNode::createFromDictionary(element); - _allNodes.emplace(node->nodeName(), node); + _allNodes.emplace(node->name(), node); _nodes.push_back(node); } // Print the tree - printTree(_root); + //printTree(_root); } void SceneGraph::printChildren() const @@ -373,7 +603,7 @@ SceneGraphNode* SceneGraph::root() const { return _root; } - + SceneGraphNode* SceneGraph::sceneGraphNode(const std::string& name) const { auto it = _allNodes.find(name); if (it == _allNodes.end()) @@ -382,4 +612,27 @@ SceneGraphNode* SceneGraph::sceneGraphNode(const std::string& name) const { return it->second; } +scripting::ScriptEngine::LuaLibrary SceneGraph::luaLibrary() { + scripting::ScriptEngine::LuaLibrary sceneGraphLibrary = { + "", + { + { + "setPropertyValue", + &luascriptfunctions::property_setValue, + "setPropertyValue(string, *): Sets a property identified by the URI in " + "the first argument. The second argument can be any type, but it has to " + " agree with the type that the property expects" + }, + { + "getPropertyValue", + &luascriptfunctions::property_getValue, + "getPropertyValue(string): Returns the value the property, identified by " + "the provided URI, has" + } + } + }; + + return std::move(sceneGraphLibrary); +} + } // namespace openspace diff --git a/src/scenegraph/scenegraphnode.cpp b/src/scenegraph/scenegraphnode.cpp index 6451674a46..b11c7c185c 100644 --- a/src/scenegraph/scenegraphnode.cpp +++ b/src/scenegraph/scenegraphnode.cpp @@ -40,11 +40,17 @@ #include #include +#include + +#include + namespace { const std::string _loggerCat = "SceneGraphNode"; } namespace openspace { + +std::string SceneGraphNode::RootNodeName = "Root"; SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& dictionary) { @@ -61,22 +67,27 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di << keyName << "' key"); return nullptr; } - dictionary.getValue(keyName, result->_nodeName); + std::string name; + dictionary.getValue(keyName, name); + result->setName(name); if (dictionary.hasValue(keyRenderable)) { ghoul::Dictionary renderableDictionary; dictionary.getValue(keyRenderable, renderableDictionary); + + renderableDictionary.setValue(keyName, name); renderableDictionary.setValue(keyPathModule, path); - renderableDictionary.setValue(keyName, result->_nodeName); result->_renderable = Renderable::createFromDictionary(renderableDictionary); if (result->_renderable == nullptr) { LERROR("Failed to create renderable for SceneGraphNode '" - << result->_nodeName << "'"); + << result->name() << "'"); return nullptr; } - LDEBUG("Successfully create renderable for '" << result->_nodeName << "'"); + result->addPropertySubOwner(result->_renderable); + LDEBUG("Successfully create renderable for '" << result->name() << "'"); } + if (dictionary.hasKey(keyEphemeris)) { ghoul::Dictionary ephemerisDictionary; dictionary.getValue(keyEphemeris, ephemerisDictionary); @@ -84,10 +95,11 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di result->_ephemeris = Ephemeris::createFromDictionary(ephemerisDictionary); if (result->_ephemeris == nullptr) { LERROR("Failed to create ephemeris for SceneGraphNode '" - << result->_nodeName << "'"); + << result->name() << "'"); return nullptr; } - LDEBUG("Successfully create ephemeris for '" << result->_nodeName << "'"); + //result->addPropertySubOwner(result->_ephemeris); + LDEBUG("Successfully create ephemeris for '" << result->name() << "'"); } std::string parentName; @@ -96,23 +108,22 @@ SceneGraphNode* SceneGraphNode::createFromDictionary(const ghoul::Dictionary& di parentName = "Root"; } - SceneGraphNode* parentNode = getSceneGraphNode(parentName); + SceneGraphNode* parentNode = sceneGraphNode(parentName); if (parentNode == nullptr) { LFATAL("Could not find parent named '" - << parentName << "' for '" << result->_nodeName << "'." + << parentName << "' for '" << result->name() << "'." << " Check module definition order. Skipping module."); } parentNode->addNode(result); LDEBUG("Successfully created SceneGraphNode '" - << result->_nodeName << "'"); + << result->name() << "'"); return result; } SceneGraphNode::SceneGraphNode() : _parent(nullptr) - , _nodeName("") , _ephemeris(new StaticEphemeris) , _renderable(nullptr) , _renderableVisible(false) @@ -137,7 +148,7 @@ bool SceneGraphNode::initialize() bool SceneGraphNode::deinitialize() { - LDEBUG("Deinitialize: " << _nodeName); + LDEBUG("Deinitialize: " << name()); delete _renderable; _renderable = nullptr; @@ -151,7 +162,6 @@ bool SceneGraphNode::deinitialize() // reset variables _parent = nullptr; - _nodeName = ""; _renderableVisible = false; _boundingSphereVisible = false; _boundingSphere = PowerScaledScalar(0.0, 0.0); @@ -175,16 +185,20 @@ void SceneGraphNode::evaluate(const Camera* camera, const psc& parentPosition) _boundingSphereVisible = false; _renderableVisible = false; +#ifndef OPENSPACE_VIDEO_EXPORT // check if camera is outside the node boundingsphere /* if (toCamera.length() > _boundingSphere) { // check if the boudningsphere is visible before avaluating children if (!sphereInsideFrustum(thisPosition, _boundingSphere, camera)) { // the node is completely outside of the camera view, stop evaluating this // node + //LFATAL(_nodeName << " is outside of frustum"); return; } } */ +#endif + // inside boudningsphere or parts of the sphere is visible, individual // children needs to be evaluated _boundingSphereVisible = true; @@ -192,12 +206,14 @@ void SceneGraphNode::evaluate(const Camera* camera, const psc& parentPosition) // this node has an renderable if (_renderable) { // check if the renderable boundingsphere is visible - _renderableVisible = true;// sphereInsideFrustum(thisPosition, _renderable->getBoundingSphere(), camera); + // _renderableVisible = sphereInsideFrustum( + // thisPosition, _renderable->getBoundingSphere(), camera); + _renderableVisible = true; } // evaluate all the children, tail-recursive function(?) for (auto& child : _children) { - child->evaluate(camera, psc()); + child->evaluate(camera, thisPosition); } } @@ -210,7 +226,7 @@ void SceneGraphNode::render(const Camera* camera, const psc& parentPosition) return; }*/ - if (_renderableVisible) { + if (_renderableVisible && _renderable->isVisible()) { // LDEBUG("Render"); _renderable->render(camera, thisPosition); } @@ -230,36 +246,28 @@ void SceneGraphNode::addNode(SceneGraphNode* child) _children.push_back(child); } -void SceneGraphNode::setName(const std::string& name) -{ - _nodeName = name; -} - void SceneGraphNode::setParent(SceneGraphNode* parent) { _parent = parent; } -const psc& SceneGraphNode::getPosition() const +const psc& SceneGraphNode::position() const { return _ephemeris->position(); } -psc SceneGraphNode::getWorldPosition() const +psc SceneGraphNode::worldPosition() const { // recursive up the hierarchy if there are parents available if (_parent) { - return _ephemeris->position() + _parent->getWorldPosition(); + return _ephemeris->position() + _parent->worldPosition(); } else { return _ephemeris->position(); } } -std::string SceneGraphNode::nodeName() const{ - return _nodeName; -} - -SceneGraphNode* SceneGraphNode::parent() const{ +SceneGraphNode* SceneGraphNode::parent() const +{ return _parent; } const std::vector& SceneGraphNode::children() const{ @@ -279,20 +287,27 @@ PowerScaledScalar SceneGraphNode::calculateBoundingSphere(){ for (size_t i = 0; i < _children.size(); ++i) { // when positions is dynamic, change this part to fins the most distant // position - PowerScaledScalar child = _children.at(i)->getPosition().length() + PowerScaledScalar child = _children.at(i)->position().length() + _children.at(i)->calculateBoundingSphere(); if (child > maxChild) { maxChild = child; } } _boundingSphere += maxChild; - } else { // leaf + } - // if has a renderable, use that boundingsphere - if (_renderable) - _boundingSphere += _renderable->getBoundingSphere(); + // if has a renderable, use that boundingsphere + if (_renderable ) { + PowerScaledScalar renderableBS = _renderable->getBoundingSphere(); + if(renderableBS > _boundingSphere) + _boundingSphere = renderableBS; } - + LWARNING(name() << ": " << _boundingSphere); + + return _boundingSphere; +} + +PowerScaledScalar SceneGraphNode::boundingSphere() const{ return _boundingSphere; } @@ -302,7 +317,8 @@ void SceneGraphNode::setRenderable(Renderable* renderable) { update(); } -const Renderable* SceneGraphNode::getRenderable() const{ +const Renderable* SceneGraphNode::renderable() const +{ return _renderable; } @@ -338,13 +354,13 @@ bool SceneGraphNode::sphereInsideFrustum(const psc s_pos, const PowerScaledScala } } -SceneGraphNode* SceneGraphNode::get(const std::string& name) +SceneGraphNode* SceneGraphNode::childNode(const std::string& name) { - if (_nodeName == name) + if (this->name() == name) return this; else for (auto it : _children) { - SceneGraphNode* tmp = it->get(name); + SceneGraphNode* tmp = it->childNode(name); if (tmp != nullptr) { return tmp; } @@ -354,7 +370,7 @@ SceneGraphNode* SceneGraphNode::get(const std::string& name) void SceneGraphNode::print() const { - std::cout << _nodeName << std::endl; + std::cout << name() << std::endl; for (auto it : _children) { it->print(); } diff --git a/src/scenegraph/spiceephemeris.cpp b/src/scenegraph/spiceephemeris.cpp index 69dc501e17..482a60d61e 100644 --- a/src/scenegraph/spiceephemeris.cpp +++ b/src/scenegraph/spiceephemeris.cpp @@ -24,32 +24,49 @@ #include +#include #include +namespace { + const std::string _loggerCat = "SpiceEphemeris"; +} + namespace openspace { -SpiceEphemeris::SpiceEphemeris(const ghoul::Dictionary& dictionary): _targetName(""), - _originName(""), - _target(0), - _origin(0), - _position() +using namespace constants::spiceephemeris; + +SpiceEphemeris::SpiceEphemeris(const ghoul::Dictionary& dictionary) + : _targetName("") + , _originName("") + , _target(0) + , _origin(0) + , _position() { - dictionary.getValue("Body", _targetName); - dictionary.getValue("Observer", _originName); + const bool hasBody = dictionary.hasKeyAndValue(keyBody); + if (hasBody) + dictionary.getValue(keyBody, _targetName); + else + LERROR("SpiceEphemeris does not contain the key '" << keyBody << "'"); + + const bool hasObserver = dictionary.hasKeyAndValue(keyOrigin); + if (hasObserver) + dictionary.getValue(keyOrigin, _originName); + else + LERROR("SpiceEphemeris does not contain the key '" << keyOrigin << "'"); } + SpiceEphemeris::~SpiceEphemeris() {} -bool SpiceEphemeris::initialize() { - - if (_targetName != "" && _originName != "") { +bool SpiceEphemeris::initialize() +{ + if (!_targetName.empty() && !_originName.empty()) { int bsuccess = 0; int osuccess = 0; Spice::ref().bod_NameToInt(_targetName, &_target, &bsuccess); Spice::ref().bod_NameToInt(_originName, &_origin, &osuccess); - if (bsuccess && osuccess) { + if (bsuccess && osuccess) return true; - } } return false; diff --git a/src/scenegraph/staticephemeris.cpp b/src/scenegraph/staticephemeris.cpp index f87e737c0e..fc1cc8ea18 100644 --- a/src/scenegraph/staticephemeris.cpp +++ b/src/scenegraph/staticephemeris.cpp @@ -24,31 +24,27 @@ #include +#include + namespace openspace { -StaticEphemeris::StaticEphemeris(const ghoul::Dictionary& dictionary) { - double x = 0.0, y = 0.0, z = 0.0, e = 0.0; - if (dictionary.hasKey("Position.1")) { - dictionary.getValue("Position.1", x); - dictionary.getValue("Position.2", y); - dictionary.getValue("Position.3", z); - dictionary.getValue("Position.4", e); +using namespace constants::staticephemeris; + +StaticEphemeris::StaticEphemeris(const ghoul::Dictionary& dictionary) + : _position(0.f, 0.f, 0.f, 0.f) +{ + const bool hasPosition = dictionary.hasKeyAndValue(keyPosition); + if (hasPosition) { + glm::vec4 tmp; + dictionary.getValue(keyPosition, tmp); + _position = tmp; } - _position = psc(x, y, z, e); } StaticEphemeris::~StaticEphemeris() {} -bool StaticEphemeris::initialize() { - return true; -} - -const psc& StaticEphemeris::position() const { +const psc& StaticEphemeris::position() const { return _position; } -void StaticEphemeris::update() { - -} - } // namespace openspace \ No newline at end of file diff --git a/src/scripting/scriptengine.cpp b/src/scripting/scriptengine.cpp new file mode 100644 index 0000000000..6e64d380c2 --- /dev/null +++ b/src/scripting/scriptengine.cpp @@ -0,0 +1,393 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include + +#include +#include + +namespace openspace { + +namespace luascriptfunctions { + + void printInternal(ghoul::logging::LogManager::LogLevel level, lua_State* L) { + using ghoul::lua::luaTypeToString; + const std::string _loggerCat = "print"; + + const int type = lua_type(L, -1); + switch (type) { + case LUA_TNONE: + case LUA_TLIGHTUSERDATA: + case LUA_TTABLE: + case LUA_TFUNCTION: + case LUA_TUSERDATA: + case LUA_TTHREAD: + LOG(level, "Function parameter was of type '" << + luaTypeToString(type) << "'"); + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + LOG(level, lua_toboolean(L, -1)); + break; + case LUA_TNUMBER: + LOG(level, lua_tonumber(L, -1)); + break; + case LUA_TSTRING: + LOG(level, lua_tostring(L, -1)); + break; + } + } + + /** + * \ingroup LuaScripts + * printDebug(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Debug'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ + int printDebug(lua_State* L) { + printInternal(ghoul::logging::LogManager::LogLevel::Debug, L); + return 0; + } + + /** + * \ingroup LuaScripts + * printInfo(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Info'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ + int printInfo(lua_State* L) { + printInternal(ghoul::logging::LogManager::LogLevel::Info, L); + return 0; + } + + /** + * \ingroup LuaScripts + * printWarning(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Warning'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ + int printWarning(lua_State* L) { + printInternal(ghoul::logging::LogManager::LogLevel::Warning, L); + return 0; + } + + /** + * \ingroup LuaScripts + * printError(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Error'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ + int printError(lua_State* L) { + printInternal(ghoul::logging::LogManager::LogLevel::Error, L); + return 0; + } + + /** + * \ingroup LuaScripts + * printFatal(*): + * Logs the passed value to the installed LogManager with a LogLevel of 'Fatal'. + * For Boolean, numbers, and strings, the internal values are printed, for all other + * types, the type is printed instead + */ + int printFatal(lua_State* L) { + printInternal(ghoul::logging::LogManager::LogLevel::Fatal, L); + return 0; + } + +} // namespace luascriptfunctions + +namespace scripting { + +namespace { + const std::string _loggerCat = "ScriptEngine"; + + const std::string _openspaceLibraryName = "openspace"; + const std::string _luaGlobalNamespace = "_G"; + const std::string _printFunctionName = "print"; + const lua_CFunction _printFunctionReplacement = luascriptfunctions::printInfo; + + const int _setTableOffset = -3; // -1 (top) -1 (first argument) -1 (second argument) + +} + +bool ScriptEngine::LuaLibrary::operator<(const LuaLibrary& rhs) const { + return name < rhs.name; +} + +ScriptEngine::ScriptEngine() + : _state(nullptr) +{ +} + +bool ScriptEngine::initialize() { + _state = luaL_newstate(); + LDEBUG("Creating Lua state"); + if (_state == nullptr) { + LFATAL("Error creating new Lua state: Memory allocation error"); + return false; + } + LDEBUG("Open Lua libraries"); + luaL_openlibs(_state); + + LDEBUG("Add OpenSpace modules"); + + LDEBUG("Create openspace base library"); + lua_newtable(_state); + lua_setglobal(_state, _openspaceLibraryName.c_str()); + + LDEBUG("Adding base functions"); + addBaseLibrary(); + + LDEBUG("Remap print function"); + remapPrintFunction(); + + return true; +} + +void ScriptEngine::deinitialize() { + lua_close(_state); + _state = nullptr; +} + +bool ScriptEngine::addLibrary(const ScriptEngine::LuaLibrary& library) { + assert(_state); + if (library.functions.empty()) { + LERROR("Lua library '" << library.name << "' does not have any functions"); + return false; + } + + //ghoul::lua::logStack(_state); + lua_getglobal(_state, _openspaceLibraryName.c_str()); + //ghoul::lua::logStack(_state); + if (library.name.empty()) { + //ghoul::lua::logStack(_state); + addLibraryFunctions(library, true); + //ghoul::lua::logStack(_state); + lua_pop(_state, 1); + //ghoul::lua::logStack(_state); + } + else { + const bool allowed = isLibraryNameAllowed(library.name); + if (!allowed) + return false; + + //ghoul::lua::logStack(_state); + + lua_pushstring(_state, library.name.c_str()); + //ghoul::lua::logStack(_state); + lua_newtable(_state); + //ghoul::lua::logStack(_state); + addLibraryFunctions(library, false); + lua_settable(_state, _setTableOffset); + //ghoul::lua::logStack(_state); + + _registeredLibraries.insert(library); + } + + return true; +} + +bool ScriptEngine::runScript(const std::string& script) { + if (script.empty()) + return false; + int status = luaL_loadstring(_state, script.c_str()); + if (status != LUA_OK) { + LERROR("Error loading script: '" << lua_tostring(_state, -1) << "'"); + return false; + } + + LDEBUG("Executing script"); + if (lua_pcall(_state, 0, LUA_MULTRET, 0)) { + LERROR("Error executing script: " << lua_tostring(_state, -1)); + return false; + } + + return true; +} + +bool ScriptEngine::runScriptFile(const std::string& filename) { + if (filename.empty()) { + LWARNING("Filename was empty"); + return false; + } + if (!FileSys.fileExists(filename)) { + LERROR("Script with name '" << filename << "' did not exist"); + return false; + } + std::ifstream file(filename.c_str()); + if (file.bad()) { + LERROR("Error opening file '" << filename << "'"); + return false; + } + + // Read the contents of the script + std::string script((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); + + const bool runSuccess = runScript(script); + return runSuccess; +} + +bool ScriptEngine::hasLibrary(const std::string& name) +{ + for (auto it = _registeredLibraries.begin(); it != _registeredLibraries.end(); ++it) + if (it->name == name) + return true; + return false; +} + +bool ScriptEngine::isLibraryNameAllowed(const std::string& name) +{ + bool result = false; + lua_getglobal(_state, _openspaceLibraryName.c_str()); + const bool hasOpenSpaceLibrary = lua_istable(_state, -1); + if (!hasOpenSpaceLibrary) { + LFATAL("OpenSpace library was not created in initialize method"); + return false; + } + lua_getfield(_state, -1, name.c_str()); + const int type = lua_type(_state, -1); + switch (type) { + case LUA_TNONE: + case LUA_TNIL: + result = true; + break; + case LUA_TBOOLEAN: + LERROR("Library name '" << name << "' specifies a boolean"); + break; + case LUA_TLIGHTUSERDATA: + LERROR("Library name '" << name << "' specifies a light user data"); + break; + case LUA_TNUMBER: + LERROR("Library name '" << name << "' specifies a number"); + break; + case LUA_TSTRING: + LERROR("Library name '" << name << "' specifies a string"); + break; + case LUA_TTABLE: { + if (hasLibrary(name)) + LERROR("Library with name '" << name << "' has been registered before"); + else + LERROR("Library name '" << name << "' specifies a table"); + break; + } + case LUA_TFUNCTION: + LERROR("Library name '" << name << "' specifies a function"); + break; + case LUA_TUSERDATA: + LERROR("Library name '" << name << "' specifies a user data"); + break; + case LUA_TTHREAD: + LERROR("Library name '" << name << "' specifies a thread"); + break; + } + + lua_pop(_state, 2); + return result; +} + +void ScriptEngine::addLibraryFunctions(const LuaLibrary& library, bool replace) +{ + for (LuaLibrary::Function p : library.functions) { + if (!replace) { + //ghoul::lua::logStack(_state); + lua_getfield(_state, -1, p.name.c_str()); + //ghoul::lua::logStack(_state); + const bool isNil = lua_isnil(_state, -1); + if (!isNil) { + LERROR("Function name '" << p.name << "' was already assigned"); + return; + } + lua_pop(_state, 1); + } + //ghoul::lua::logStack(_state); + lua_pushstring(_state, p.name.c_str()); + //ghoul::lua::logStack(_state); + lua_pushcfunction(_state, p.function); + //ghoul::lua::logStack(_state); + lua_settable(_state, _setTableOffset); + //ghoul::lua::logStack(_state); + } +} + +void ScriptEngine::addBaseLibrary() { + LuaLibrary lib = { + "", + { + { + "printDebug", + &luascriptfunctions::printDebug, + "printDebug(*): Logs the passed value to the installed LogManager with a " + "LogLevel of 'Debug'" + }, + { + "printInfo", + &luascriptfunctions::printInfo, + "printInfo(*): Logs the passed value to the installed LogManager with a " + " LogLevel of 'Info'" + }, + { + "printWarning", + &luascriptfunctions::printWarning, + "printWarning(*): Logs the passed value to the installed LogManager with " + "a LogLevel of 'Warning'" + }, + { + "printError", + &luascriptfunctions::printError, + "printError(*): Logs the passed value to the installed LogManager with a " + "LogLevel of 'Error'" + }, + { + "printFatal", + &luascriptfunctions::printFatal, + "printFatal(*): Logs the passed value to the installed LogManager with a " + "LogLevel of 'Fatal'" + } + } + }; + addLibrary(lib); +} + +void ScriptEngine::remapPrintFunction() { + //ghoul::lua::logStack(_state); + // lua_getglobal(_state, _luaGlobalNamespace.c_str()); + //ghoul::lua::logStack(_state); + // lua_pushstring(_state, _printFunctionName.c_str()); + //ghoul::lua::logStack(_state); + // lua_pushcfunction(_state, _printFunctionReplacement); + //ghoul::lua::logStack(_state); + // lua_settable(_state, _setTableOffset); + //ghoul::lua::logStack(_state); +} + +} // namespace scripting +} // namespace openspace diff --git a/src/tests/main.cpp b/src/tests/main.cpp index 43f4fe2c2f..b65a6237fd 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -1,9 +1,8 @@ /***************************************************************************************** * * - * GHOUL * - * General Helpful Open Utility Library * + * OpenSpace * * * - * Copyright (c) 2012-2014 * + * Copyright (c) 2014 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * @@ -34,7 +33,8 @@ #include #include //#include -//#include +#include +#include #include #include #include @@ -64,7 +64,7 @@ int main(int argc, char** argv) { } LINFO("Configuration file found: " << FileSys.absolutePath(configurationFilePath)); - LDEBUG("registering base path"); + LDEBUG("Registering base path"); if( ! openspace::OpenSpaceEngine::registerBasePathFromConfigurationFile(configurationFilePath)) { LFATAL("Could not register base path"); assert(false); @@ -79,9 +79,6 @@ int main(int argc, char** argv) { } } - /*openspace::Time::init(); - openspace::Spice::init(); - openspace::Spice::ref().loadDefaultKernels();*/ openspace::FactoryManager::initialize(); testing::InitGoogleTest(&argc, argv); diff --git a/src/util/factorymanager.cpp b/src/util/factorymanager.cpp index 969efde3ac..8d17930a14 100644 --- a/src/util/factorymanager.cpp +++ b/src/util/factorymanager.cpp @@ -28,6 +28,7 @@ // renderables #include +#include #include #include #include @@ -58,13 +59,11 @@ void FactoryManager::initialize() "RenderablePlanet"); _manager->factory()->registerClass( "RenderableStars"); - _manager->factory()->registerClass( - "RenderableVolumeCL"); + //_manager->factory()->registerClass( + // "RenderableVolumeCL"); _manager->factory()->registerClass( "RenderableVolumeGL"); - _manager->factory()->registerClass( - "RenderableVolumeExpert"); - _manager->factory()->registerClass("RenderableFlare"); + _manager->factory()->registerClass("RenderableFieldlines"); // Add Ephimerides _manager->addFactory(new ghoul::TemplateFactory); @@ -105,4 +104,4 @@ void FactoryManager::addFactory(ghoul::TemplateFactoryBase* factory) { } -} // namespace openspace \ No newline at end of file +} // namespace openspace diff --git a/src/util/kameleonwrapper.cpp b/src/util/kameleonwrapper.cpp index 66db1fb2d9..ce0acd5376 100644 --- a/src/util/kameleonwrapper.cpp +++ b/src/util/kameleonwrapper.cpp @@ -31,8 +31,12 @@ #include #define _USE_MATH_DEFINES #include - +#include +#include #include +#include + +#include namespace openspace { @@ -42,23 +46,33 @@ KameleonWrapper::KameleonWrapper(const std::string& filename, Model model): _typ switch (_type) { case Model::BATSRUS: _model = new ccmc::BATSRUS(); - if(!_model) LERROR("BATSRUS:Failed to create model instance"); + if(!_model) LERROR("BATSRUS:Failed to create BATSRUS model instance"); if (_model->open(filename) != ccmc::FileReader::OK) LERROR("BATSRUS:Failed to open "+filename); _interpolator = _model->createNewInterpolator(); - if (!_interpolator) LERROR("BATSRUS:Failed to create interpolator"); + if (!_interpolator) LERROR("BATSRUS:Failed to create BATSRUS interpolator"); break; case Model::ENLIL: _model = new ccmc::ENLIL(); - if(!_model) LERROR("Failed to create model instance"); + if(!_model) LERROR("Failed to create ENLIL model instance"); if (_model->open(filename) != ccmc::FileReader::OK) LERROR("Failed to open "+filename); _interpolator = _model->createNewInterpolator(); - if (!_interpolator) LERROR("Failed to create interpolator"); + if (!_interpolator) LERROR("Failed to create ENLIL interpolator"); break; default: LERROR("No valid model type provided!"); } + + getGridVariables(_xCoordVar, _yCoordVar, _zCoordVar); + _xMin = _model->getVariableAttribute(_xCoordVar, "actual_min").getAttributeFloat(); + _xMax = _model->getVariableAttribute(_xCoordVar, "actual_max").getAttributeFloat(); + _yMin = _model->getVariableAttribute(_yCoordVar, "actual_min").getAttributeFloat(); + _yMax = _model->getVariableAttribute(_yCoordVar, "actual_max").getAttributeFloat(); + _zMin = _model->getVariableAttribute(_zCoordVar, "actual_min").getAttributeFloat(); + _zMax = _model->getVariableAttribute(_zCoordVar, "actual_max").getAttributeFloat(); + + _lastiProgress = -1; // For progressbar } KameleonWrapper::~KameleonWrapper() { @@ -70,93 +84,34 @@ float* KameleonWrapper::getUniformSampledValues(const std::string& var, glm::siz assert(_model && _interpolator); assert(outDimensions.x > 0 && outDimensions.y > 0 && outDimensions.z > 0); assert(_type == Model::ENLIL || _type == Model::BATSRUS); - LINFO("Loading CDF data"); + LINFO("Loading variable " << var << " from CDF data with a uniform sampling"); int size = outDimensions.x*outDimensions.y*outDimensions.z; float* data = new float[size]; - - // get the grid system string - std::string gridSystem = _model->getGlobalAttribute("grid_system_1").getAttributeString(); - - // remove leading and trailing brackets - gridSystem = gridSystem.substr(1,gridSystem.length()-2); - - // remove all whitespaces - gridSystem.erase(remove_if(gridSystem.begin(), gridSystem.end(), isspace), gridSystem.end()); - - // replace all comma signs with whitespaces - std::replace( gridSystem.begin(), gridSystem.end(), ',', ' '); - - // tokenize - std::istringstream iss(gridSystem); - std::vector tokens{std::istream_iterator{iss},std::istream_iterator{}}; - - // validate - if (tokens.size() != 3) { - LERROR("Something went wrong"); - delete[] data; - return 0; - } + double* doubleData = new double[size]; - std::string v_x = tokens.at(0), v_y = tokens.at(1), v_z = tokens.at(2); - /* - for(auto t: tokens) - LDEBUG("t: " << t); - */ - /* - LERROR("getVariableAttributeNames"); - std::vector attributeNames = _model->getVariableAttributeNames(); - for(auto name : attributeNames) - LDEBUG(name); - */ - //_model->getVa + double varMin = _model->getVariableAttribute(var, "actual_min").getAttributeFloat(); + double varMax = _model->getVariableAttribute(var, "actual_max").getAttributeFloat(); + + double stepX = (_xMax-_xMin)/(static_cast(outDimensions.x)); + double stepY = (_yMax-_yMin)/(static_cast(outDimensions.y)); + double stepZ = (_zMax-_zMin)/(static_cast(outDimensions.z)); - //auto fan = std::find(attributeNames.begin(), attributeNames.end(), ""); - - - //KameleonWrapper (Debug) grid_system_1 - //KameleonWrapper (Debug) grid_1_type - - LDEBUG("Using coordinate system: " << v_x << ", " << v_y << ", " << v_z); - - float xMin = _model->getVariableAttribute(v_x, "actual_min").getAttributeFloat(); - float xMax = _model->getVariableAttribute(v_x, "actual_max").getAttributeFloat(); - float yMin = _model->getVariableAttribute(v_y, "actual_min").getAttributeFloat(); - float yMax = _model->getVariableAttribute(v_y, "actual_max").getAttributeFloat(); - float zMin = _model->getVariableAttribute(v_z, "actual_min").getAttributeFloat(); - float zMax = _model->getVariableAttribute(v_z, "actual_max").getAttributeFloat(); - float varMin = _model->getVariableAttribute(var, "actual_min").getAttributeFloat(); - float varMax = _model->getVariableAttribute(var, "actual_max").getAttributeFloat(); - - float stepX = (xMax-xMin)/(static_cast(outDimensions.x)); - float stepY = (yMax-yMin)/(static_cast(outDimensions.y)); - float stepZ = (zMax-zMin)/(static_cast(outDimensions.z)); - - - LDEBUG(v_x << "Min: " << xMin); - LDEBUG(v_x << "Max: " << xMax); - LDEBUG(v_y << "Min: " << yMin); - LDEBUG(v_y << "Max: " << yMax); - LDEBUG(v_z << "Min: " << zMin); - LDEBUG(v_z << "Max: " << zMax); LDEBUG(var << "Min: " << varMin); LDEBUG(var << "Max: " << varMax); + + // HISTOGRAM + const int bins = 200; + const float truncLim = 0.9; + std::vector histogram (bins,0); + auto mapToHistogram = [varMin, varMax, bins](double val) { + double zeroToOne = (val-varMin)/(varMax-varMin); + zeroToOne *= static_cast(bins); + return static_cast(zeroToOne); + }; - int barWidth = 70; - int lastiProgress = -1; for (int x = 0; x < outDimensions.x; ++x) { - float progress = static_cast(x) / static_cast(outDimensions.x-1); - int iprogress = static_cast(progress*100.0f); - if (iprogress != lastiProgress) { - - int pos = barWidth * progress; - int eqWidth = pos+1; - int spWidth = barWidth - pos + 2; - std::cout << "[" << std::setfill('=') << std::setw(eqWidth) - << ">" << std::setfill(' ') << std::setw(spWidth) - << "] " << iprogress << " % \r" << std::flush; - } - lastiProgress = iprogress; + progressBar(x, outDimensions.x); for (int y = 0; y < outDimensions.y; ++y) { for (int z = 0; z < outDimensions.z; ++z) { @@ -164,46 +119,40 @@ float* KameleonWrapper::getUniformSampledValues(const std::string& var, glm::siz int index = x + y*outDimensions.x + z*outDimensions.x*outDimensions.y; if(_type == Model::BATSRUS) { - float xPos = xMin + stepX*x; - float yPos = yMin + stepY*y; - float zPos = zMin + stepZ*z; + double xPos = _xMin + stepX*x; + double yPos = _yMin + stepY*y; + double zPos = _zMin + stepZ*z; // get interpolated data value for (xPos, yPos, zPos) - float value = _interpolator->interpolate(var, xPos, yPos, zPos); - - // scale to [0,1] - data[index] = (value-varMin)/(varMax-varMin); + // swap yPos and zPos because model has Z as up + double value = _interpolator->interpolate(var, xPos, zPos, yPos); + doubleData[index] = value; + histogram[mapToHistogram(value)]++; + } else if (_type == Model::ENLIL) { - //LDEBUG("data: " << theval); - - // Calculate array index - //unsigned int index = r + theta*xDim_ + phi*xDim_*yDim_; // Put r in the [0..sqrt(3)] range - float rNorm = sqrt(3.0)*(float)x/(float)(outDimensions.x-1); + double rNorm = sqrt(3.0)*(double)x/(double)(outDimensions.x-1); // Put theta in the [0..PI] range - float thetaNorm = M_PI*(float)y/(float)(outDimensions.y-1); + double thetaNorm = M_PI*(double)y/(double)(outDimensions.y-1); // Put phi in the [0..2PI] range - float phiNorm = 2.0*M_PI*(float)z/(float)(outDimensions.z-1); + double phiNorm = 2.0*M_PI*(double)z/(double)(outDimensions.z-1); // Go to physical coordinates before sampling - float rPh = xMin + rNorm*(xMax-xMin); - float thetaPh = thetaNorm; - //phi range needs to be mapped to the slightly different - // model range to avoid gaps in the data - // Subtract a small term to avoid rounding errors when comparing - // to phiMax. - float phiPh = zMin + phiNorm/(2.0*M_PI)*(zMax-zMin-0.000001); + double rPh = _xMin + rNorm*(_xMax-_xMin); + double thetaPh = thetaNorm; + // phi range needs to be mapped to the slightly different model + // range to avoid gaps in the data Subtract a small term to + // avoid rounding errors when comparing to phiMax. + double phiPh = _zMin + phiNorm/(2.0*M_PI)*(_zMax-_zMin-0.000001); - // Hardcoded variables (rho or rho - rho_back) - // TODO Don't hardcode, make more flexible - float varValue = 0.f;//, rho_back = 0.f, diff = 0.f; + double value = 0.0; // See if sample point is inside domain - if (rPh < xMin || rPh > xMax || thetaPh < yMin || - thetaPh > yMax || phiPh < zMin || phiPh > zMax) { - if (phiPh > zMax) { + if (rPh < _xMin || rPh > _xMax || thetaPh < _yMin || + thetaPh > _yMax || phiPh < _zMin || phiPh > _zMax) { + if (phiPh > _zMax) { std::cout << "Warning: There might be a gap in the data\n"; } // Leave values at zero if outside domain @@ -217,23 +166,12 @@ float* KameleonWrapper::getUniformSampledValues(const std::string& var, glm::siz // Convert from [0, 2pi] rad to [0, 360] degrees phiPh = phiPh*180.f/M_PI; // Sample - varValue = _interpolator->interpolate(var, rPh, thetaPh, phiPh); - //rho_back = _interpolator->interpolate("rho-back",rPh,thetaPh,phiPh); - - // Calculate difference (or just rho) - //diff = rho; - //diff = rho - rho_back; - - // Clamp to 0 - //if (diff < 0.f) diff = 0.f; + value = _interpolator->interpolate(var, rPh, thetaPh, phiPh); + // value = _interpolator->interpolate(var, rPh, phiPh, thetaPh); } - //if(var < 0.0f) var = 0.0f; - //data[index] = var; - data[index] = (varValue-varMin)/(varMax-varMin); - //LDEBUG("varValue:" << varValue); - //LDEBUG("data[index]:" << data[index]); - //data[index] = var; - //data[index] = diff; + + doubleData[index] = value; + histogram[mapToHistogram(value)]++; } } } @@ -241,8 +179,450 @@ float* KameleonWrapper::getUniformSampledValues(const std::string& var, glm::siz std::cout << std::endl; LINFO("Done!"); + // for (int i = 0; i < outDimensions.x * outDimensions.y * outDimensions.z; ++i) + // { + // std::cout << std::setfill(' ') << std::setw(15) << doubleData[i] << ", "; + // if(i % 10 == 0) + // std::cout << std::endl; + // } + // + // for(int i = 0; i < bins-1; ++i) { + // // sum += histogram[i]; + // // if(sum + histogram[i+1] > sumuntil) { + // // stop = i; + // // LDEBUG("===================="); + // // break; + // // } + // LDEBUG("histogram[" << i << "]: " << histogram[i]); + // } + + int sum = 0; + int stop; + const int sumuntil = size * truncLim; + for(int i = 0; i < bins; ++i) { + sum += histogram[i]; + if(sum > sumuntil) { + stop = i; + // LDEBUG("===================="); + break; + } + // LDEBUG("histogram[" << i << "]: " << histogram[i]); + } + + double dist = varMax - varMin; + dist = (dist / static_cast(bins)) * static_cast(stop); + + varMax = varMin + dist; + LDEBUG(var << "Min: " << varMin); + LDEBUG(var << "Max: " << varMax); + for(int i = 0; i < size; ++i) { + double normalizedVal = (doubleData[i]-varMin)/(varMax-varMin); + + data[i] = static_cast(glm::clamp(normalizedVal, 0.0, 1.0)); + if(data[i] < 0.0) { + LERROR("Datapoint " << i << " less than 0"); + } + if(data[i] > 1.0) { + LERROR("Datapoint " << i << " more than 1"); + } + } + + // for(int i = 0; i < size; ++i) { + // double normalizedVal = (doubleData[i]-varMin)/(varMax-varMin); + // // data[i] = static_cast(glm::clamp(normalizedVal, 0.0, 1.0)); + // data[i] = static_cast(normalizedVal); + // } + + delete[] doubleData; return data; } -} // namespace openspace +float* KameleonWrapper::getUniformSampledVectorValues(const std::string& xVar, const std::string& yVar, const std::string& zVar, glm::size3_t outDimensions) { + assert(_model && _interpolator); + assert(outDimensions.x > 0 && outDimensions.y > 0 && outDimensions.z > 0); + assert(_type == Model::ENLIL || _type == Model::BATSRUS); + LINFO("Loading variables " << xVar << " " << yVar << " " << zVar << " from CDF data with a uniform sampling"); + int channels = 4; + int size = channels*outDimensions.x*outDimensions.y*outDimensions.z; + float* data = new float[size]; + + float varXMin = _model->getVariableAttribute(xVar, "actual_min").getAttributeFloat(); + float varXMax = _model->getVariableAttribute(xVar, "actual_max").getAttributeFloat(); + float varYMin = _model->getVariableAttribute(yVar, "actual_min").getAttributeFloat(); + float varYMax = _model->getVariableAttribute(yVar, "actual_max").getAttributeFloat(); + float varZMin = _model->getVariableAttribute(zVar, "actual_min").getAttributeFloat(); + float varZMax = _model->getVariableAttribute(zVar, "actual_max").getAttributeFloat(); + + float stepX = (_xMax-_xMin)/(static_cast(outDimensions.x)); + float stepY = (_yMax-_yMin)/(static_cast(outDimensions.y)); + float stepZ = (_zMax-_zMin)/(static_cast(outDimensions.z)); + + LDEBUG(xVar << "Min: " << varXMin); + LDEBUG(xVar << "Max: " << varXMax); + LDEBUG(yVar << "Min: " << varYMin); + LDEBUG(yVar << "Max: " << varYMax); + LDEBUG(zVar << "Min: " << varZMin); + LDEBUG(zVar << "Max: " << varZMax); + + for (int x = 0; x < outDimensions.x; ++x) { + progressBar(x, outDimensions.x); + + for (int y = 0; y < outDimensions.y; ++y) { + for (int z = 0; z < outDimensions.z; ++z) { + + int index = x*channels + y*channels*outDimensions.x + z*channels*outDimensions.x*outDimensions.y; + + if(_type == Model::BATSRUS) { + float xPos = _xMin + stepX*x; + float yPos = _yMin + stepY*y; + float zPos = _zMin + stepZ*z; + + // get interpolated data value for (xPos, yPos, zPos) + float xValue = _interpolator->interpolate(xVar, xPos, yPos, zPos); + float yValue = _interpolator->interpolate(yVar, xPos, yPos, zPos); + float zValue = _interpolator->interpolate(zVar, xPos, yPos, zPos); + + // scale to [0,1] + data[index] = (xValue-varXMin)/(varXMax-varXMin); // R + data[index + 1] = (yValue-varYMin)/(varYMax-varYMin); // G + data[index + 2] = (zValue-varZMin)/(varZMax-varZMin); // B + data[index + 3] = 1.0; // GL_RGB refuses to work. Workaround by doing a GL_RGBA with hardcoded alpha + } else { + LERROR("Only BATSRUS supported for getUniformSampledVectorValues (for now)"); + return data; + } + } + } + } + std::cout << std::endl; + LINFO("Done!"); + + return data; +} + +std::vector > KameleonWrapper::getClassifiedFieldLines( + const std::string& xVar, const std::string& yVar, + const std::string& zVar, std::vector seedPoints, + float stepSize ) { + assert(_model && _interpolator); + assert(_type == Model::ENLIL || _type == Model::BATSRUS); + LINFO("Creating " << seedPoints.size() << " fieldlines from variables " << xVar << " " << yVar << " " << zVar); + + std::vector fLine, bLine; + std::vector > fieldLines; + glm::vec4 color; + FieldlineEnd forwardEnd, backEnd; + + if (_type == Model::BATSRUS) { + for (glm::vec3 seedPoint : seedPoints) { + fLine = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, stepSize, TraceDirection::FORWARD, forwardEnd); + bLine = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, stepSize, TraceDirection::BACK, backEnd); + + bLine.insert(bLine.begin(), fLine.rbegin(), fLine.rend()); + + // classify + color = classifyFieldline(forwardEnd, backEnd); + + // write colors + std::vector line; + for (glm::vec3 position : bLine) { + line.push_back(LinePoint(position, color)); + } + + fieldLines.push_back(line); + } + } else { + LERROR("Fieldlines are only supported for BATSRUS model"); + } + + return fieldLines; +} + +std::vector > KameleonWrapper::getFieldLines( + const std::string& xVar, const std::string& yVar, + const std::string& zVar, std::vector seedPoints, + float stepSize, glm::vec4 color ) { + assert(_model && _interpolator); + assert(_type == Model::ENLIL || _type == Model::BATSRUS); + LINFO("Creating " << seedPoints.size() << " fieldlines from variables " << xVar << " " << yVar << " " << zVar); + + std::vector fLine, bLine; + std::vector > fieldLines; + FieldlineEnd forwardEnd, backEnd; + + if (_type == Model::BATSRUS) { + for (glm::vec3 seedPoint : seedPoints) { + fLine = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, stepSize, TraceDirection::FORWARD, forwardEnd); + bLine = traceCartesianFieldline(xVar, yVar, zVar, seedPoint, stepSize, TraceDirection::BACK, backEnd); + + bLine.insert(bLine.begin(), fLine.rbegin(), fLine.rend()); + + // write colors + std::vector line; + for (glm::vec3 position : bLine) { + line.push_back(LinePoint(position, color)); + } + + fieldLines.push_back(line); + } + } else { + LERROR("Fieldlines are only supported for BATSRUS model"); + } + + return fieldLines; +} + +std::vector > KameleonWrapper::getLorentzTrajectories( + std::vector seedPoints, glm::vec4 color, float stepsize) { + LINFO("Creating " << seedPoints.size() << " Lorentz force trajectories"); + + std::vector > trajectories; + std::vector plusTraj, minusTraj; + + for (auto seedPoint : seedPoints) { + plusTraj = traceLorentzTrajectory(seedPoint, stepsize, 1.0); + minusTraj = traceLorentzTrajectory(seedPoint, stepsize, -1.0); + + minusTraj.insert(minusTraj.begin(), plusTraj.rbegin(), plusTraj.rend()); + + // write colors + std::vector trajectory; + for (glm::vec3 position : minusTraj) { + trajectory.push_back(LinePoint(position, color)); + } + trajectories.push_back(trajectory); + } + + return trajectories; +} + +glm::vec3 KameleonWrapper::getModelBarycenterOffset() { + glm::vec3 offset; + offset.x = _xMin+(std::abs(_xMin)+std::abs(_xMax))/2.0f; + offset.y = _yMin+(std::abs(_yMin)+std::abs(_yMax))/2.0f; + offset.z = _zMin+(std::abs(_zMin)+std::abs(_zMax))/2.0f; + return offset; +} + +std::vector KameleonWrapper::traceCartesianFieldline( + const std::string& xVar, const std::string& yVar, + const std::string& zVar, glm::vec3 seedPoint, + float stepSize, TraceDirection direction, FieldlineEnd& end) { + + glm::vec3 color, pos, k1, k2, k3, k4; + std::vector line; + float stepX, stepY, stepZ; + int numSteps = 0, maxSteps = 5000; + pos = seedPoint; + + _model->loadVariable(xVar); + _model->loadVariable(yVar); + _model->loadVariable(zVar); + + long int xID = _model->getVariableID(xVar); + long int yID = _model->getVariableID(yVar); + long int zID = _model->getVariableID(zVar); + + // While we are inside the models boundries and not inside earth + while ((pos.x < _xMax && pos.x > _xMin && pos.y < _yMax && pos.y > _yMin && + pos.z < _zMax && pos.z > _zMin) && !(pos.x*pos.x + pos.y*pos.y + pos.z*pos.z < 1.0)) { + + // Save position. Model has +Z as up + line.push_back(glm::vec3(pos.x, pos.z, pos.y)); + + // Calculate new position with Runge-Kutta 4th order + k1.x = _interpolator->interpolate(xID, pos.x, pos.y, pos.z, stepX, stepY, stepZ); + k1.y = _interpolator->interpolate(yID, pos.x, pos.y, pos.z); + k1.z = _interpolator->interpolate(zID, pos.x, pos.y, pos.z); + k1 = (float)direction*glm::normalize(k1); + stepX=stepX*stepSize, stepY=stepY*stepSize, stepZ=stepZ*stepSize; + k2.x = _interpolator->interpolate(xID, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z); + k2.y = _interpolator->interpolate(yID, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z); + k2.z = _interpolator->interpolate(zID, pos.x+(stepX/2.0)*k1.x, pos.y+(stepY/2.0)*k1.y, pos.z+(stepZ/2.0)*k1.z); + k2 = (float)direction*glm::normalize(k2); + k3.x = _interpolator->interpolate(xID, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z); + k3.y = _interpolator->interpolate(yID, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z); + k3.z = _interpolator->interpolate(zID, pos.x+(stepX/2.0)*k2.x, pos.y+(stepY/2.0)*k2.y, pos.z+(stepZ/2.0)*k2.z); + k3 = (float)direction*glm::normalize(k3); + k4.x = _interpolator->interpolate(xID, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z); + k4.y = _interpolator->interpolate(yID, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z); + k4.z = _interpolator->interpolate(zID, pos.x+stepX*k3.x, pos.y+stepY*k3.y, pos.z+stepZ*k3.z); + k4 = (float)direction*glm::normalize(k4); + pos.x = pos.x + (stepX/6.0)*(k1.x + 2.0*k2.x + 2.0*k3.x + k4.x); + pos.y = pos.y + (stepY/6.0)*(k1.y + 2.0*k2.y + 2.0*k3.y + k4.y); + pos.z = pos.z + (stepZ/6.0)*(k1.z + 2.0*k2.z + 2.0*k3.z + k4.z); + + ++numSteps; + if (numSteps > maxSteps) { + LDEBUG("Max number of steps taken (" << maxSteps <<")"); + break; + } + } + // Save last position. Model has +Z as up + line.push_back(glm::vec3(pos.x, pos.z, pos.y)); + + if (pos.z > 0.0 && (pos.x*pos.x + pos.y*pos.y + pos.z*pos.z < 1.0)) + end = FieldlineEnd::NORTH; + else if (pos.z < 0.0 && (pos.x*pos.x + pos.y*pos.y + pos.z*pos.z < 1.0)) + end = FieldlineEnd::SOUTH; + else + end = FieldlineEnd::OUT; + + return line; +} + +std::vector KameleonWrapper::traceLorentzTrajectory(glm::vec3 seedPoint, + float stepsize, float eCharge) { + glm::vec3 B, E, v0, k1, k2, k3, k4, sPos, tmpV; + float stepX = stepsize, stepY = stepsize, stepZ = stepsize; + + long int bxID = _model->getVariableID("bx"); + long int byID = _model->getVariableID("by"); + long int bzID = _model->getVariableID("bz"); + long int jxID = _model->getVariableID("jx"); + long int jyID = _model->getVariableID("jy"); + long int jzID = _model->getVariableID("jz"); + + std::vector trajectory; + glm::vec3 pos = seedPoint; + int numSteps = 0, maxSteps = 5000; + v0.x = _interpolator->interpolate("ux", pos.x, pos.y, pos.z); + v0.y = _interpolator->interpolate("uy", pos.x, pos.y, pos.z); + v0.z = _interpolator->interpolate("uz", pos.x, pos.y, pos.z); + v0 = glm::normalize(v0); + + // While we are inside the models boundries and not inside earth + while ((pos.x < _xMax && pos.x > _xMin && pos.y < _yMax && pos.y > _yMin && + pos.z < _zMax && pos.z > _zMin) && !(pos.x*pos.x + pos.y*pos.y + pos.z*pos.z < 1.0)) { + + // Save position. Model has +Z as up + trajectory.push_back(glm::vec3(pos.x, pos.z, pos.y)); + + // Calculate new position with Lorentz force quation and Runge-Kutta 4th order + B.x = _interpolator->interpolate(bxID, pos.x, pos.y, pos.z); + B.y = _interpolator->interpolate(byID, pos.x, pos.y, pos.z); + B.z = _interpolator->interpolate(bzID, pos.x, pos.y, pos.z); + E.x = _interpolator->interpolate(jxID, pos.x, pos.y, pos.z); + E.y = _interpolator->interpolate(jyID, pos.x, pos.y, pos.z); + E.z = _interpolator->interpolate(jzID, pos.x, pos.y, pos.z); + k1 = eCharge*(E + glm::cross(v0, B)); + k1 = glm::normalize(k1); + + sPos = glm::vec3( pos.x+(stepX/2.0)*v0.x+(stepX*stepX/8.0)*k1.x, + pos.y+(stepY/2.0)*v0.y+(stepY*stepY/8.0)*k1.y, + pos.z+(stepZ/2.0)*v0.z+(stepZ*stepZ/8.0)*k1.z); + B.x = _interpolator->interpolate(bxID, sPos.x, sPos.y, sPos.z); + B.y = _interpolator->interpolate(byID, sPos.x, sPos.y, sPos.z); + B.z = _interpolator->interpolate(bzID, sPos.x, sPos.y, sPos.z); + E.x = _interpolator->interpolate(jxID, sPos.x, sPos.y, sPos.z); + E.y = _interpolator->interpolate(jyID, sPos.x, sPos.y, sPos.z); + E.z = _interpolator->interpolate(jzID, sPos.x, sPos.y, sPos.z); + tmpV = v0+(stepX/2.0f)*k1; + k2 = eCharge*(E + glm::cross(tmpV, B)); + k2 = glm::normalize(k2); + + B.x = _interpolator->interpolate(bxID, sPos.x, sPos.y, sPos.z); + B.y = _interpolator->interpolate(byID, sPos.x, sPos.y, sPos.z); + B.z = _interpolator->interpolate(bzID, sPos.x, sPos.y, sPos.z); + E.x = _interpolator->interpolate(jxID, sPos.x, sPos.y, sPos.z); + E.y = _interpolator->interpolate(jyID, sPos.x, sPos.y, sPos.z); + E.z = _interpolator->interpolate(jzID, sPos.x, sPos.y, sPos.z); + tmpV = v0+(stepX/2.0f)*k2; + k3 = eCharge*(E + glm::cross(tmpV, B)); + k3 = glm::normalize(k3); + + sPos = glm::vec3( pos.x+stepX*v0.x+(stepX*stepX/2.0)*k1.x, + pos.y+stepY*v0.y+(stepY*stepY/2.0)*k1.y, + pos.z+stepZ*v0.z+(stepZ*stepZ/2.0)*k1.z); + B.x = _interpolator->interpolate(bxID, sPos.x, sPos.y, sPos.z); + B.y = _interpolator->interpolate(byID, sPos.x, sPos.y, sPos.z); + B.z = _interpolator->interpolate(bzID, sPos.x, sPos.y, sPos.z); + E.x = _interpolator->interpolate(jxID, sPos.x, sPos.y, sPos.z); + E.y = _interpolator->interpolate(jyID, sPos.x, sPos.y, sPos.z); + E.z = _interpolator->interpolate(jzID, sPos.x, sPos.y, sPos.z); + tmpV = v0+stepX*k3; + k4 = eCharge*(E + glm::cross(tmpV, B)); + k4 = glm::normalize(k4); + + pos.x = pos.x + stepX*v0.x + (stepX*stepX/6.0)*(k1.x + k2.x + k3.x); + pos.y = pos.y + stepY*v0.y + (stepY*stepY/6.0)*(k1.y + k2.y + k3.y); + pos.z = pos.z + stepZ*v0.z + (stepZ*stepZ/6.0)*(k1.z + k2.z + k3.z); + + v0.x = v0.x + (stepX/6.0)*(k1.x + 2.0*k2.x + 2.0*k3.x + k4.z); + v0.y = v0.y + (stepY/6.0)*(k1.y + 2.0*k2.y + 2.0*k3.y + k4.y); + v0.z = v0.z + (stepZ/6.0)*(k1.z + 2.0*k2.z + 2.0*k3.z + k4.z); + + ++numSteps; + if (numSteps > maxSteps) { + LDEBUG("Max number of steps taken (" << maxSteps <<")"); + break; + } + } + // Save last position. Model has +Z as up + trajectory.push_back(glm::vec3(pos.x, pos.z, pos.y)); + return trajectory; +} + +void KameleonWrapper::getGridVariables(std::string& x, std::string& y, std::string& z) { + // get the grid system string + std::string gridSystem = _model->getGlobalAttribute("grid_system_1").getAttributeString(); + + // remove leading and trailing brackets + gridSystem = gridSystem.substr(1,gridSystem.length()-2); + + // remove all whitespaces + gridSystem.erase(remove_if(gridSystem.begin(), gridSystem.end(), isspace), gridSystem.end()); + + // replace all comma signs with whitespaces + std::replace( gridSystem.begin(), gridSystem.end(), ',', ' '); + + // tokenize + std::istringstream iss(gridSystem); + std::vector tokens{std::istream_iterator{iss},std::istream_iterator{}}; + + // validate + if (tokens.size() != 3) LERROR("Something went wrong"); + + x = tokens.at(0); + y = tokens.at(1); + z = tokens.at(2); +} + +void KameleonWrapper::progressBar(int current, int end) { + float progress = static_cast(current) / static_cast(end-1); + int iprogress = static_cast(progress*100.0f); + int barWidth = 70; + if (iprogress != _lastiProgress) { + int pos = barWidth * progress; + int eqWidth = pos+1; + int spWidth = barWidth - pos + 2; + std::cout << "[" << std::setfill('=') << std::setw(eqWidth) + << ">" << std::setfill(' ') << std::setw(spWidth) + << "] " << iprogress << " % \r" << std::flush; + } + _lastiProgress = iprogress; +} + +glm::vec4 KameleonWrapper::classifyFieldline(FieldlineEnd fEnd, FieldlineEnd bEnd) { + glm::vec4 color; + if ( (fEnd == FieldlineEnd::NORTH || fEnd == FieldlineEnd::SOUTH) + && (bEnd == FieldlineEnd::NORTH || bEnd == FieldlineEnd::SOUTH)) { + // closed + color = glm::vec4(1.0, 0.0, 0.0, 1.0); + } else if ((fEnd == FieldlineEnd::OUT && bEnd == FieldlineEnd::NORTH) + || (bEnd == FieldlineEnd::OUT && fEnd == FieldlineEnd::NORTH)) { + // north + color = glm::vec4(1.0, 1.0, 0.0, 1.0); + } else if ((fEnd == FieldlineEnd::OUT && bEnd == FieldlineEnd::SOUTH) + || (bEnd == FieldlineEnd::OUT && fEnd == FieldlineEnd::SOUTH)) { + // south + color = glm::vec4(0.0, 1.0, 0.0, 1.0); + } else if (fEnd == FieldlineEnd::OUT && bEnd == FieldlineEnd::OUT) { + // solar wind + color = glm::vec4(0.0, 0.0, 1.0, 1.0); + } + return color; +} + +} // namespace openspace diff --git a/src/util/shadercreator.cpp b/src/util/shadercreator.cpp new file mode 100644 index 0000000000..aaec11b539 --- /dev/null +++ b/src/util/shadercreator.cpp @@ -0,0 +1,195 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +// #include +// #include + +using ghoul::opengl::ProgramObject; +using ghoul::opengl::ShaderObject; + +namespace { + const std::string _loggerCat = "ShaderCreator"; + const std::string defaultSourceFileExtension = "OpenSpaceGenerated.glsl"; + const std::string separator = "//=====================================================================\n"; + const ShaderObject::ShaderType vsType = ShaderObject::ShaderType::ShaderTypeVertex; + const ShaderObject::ShaderType fsType = ShaderObject::ShaderType::ShaderTypeFragment; + const ShaderObject::ShaderType gsType = ShaderObject::ShaderType::ShaderTypeGeometry; +} + +namespace openspace { +ShaderCreator::ShaderCreator(): + _createSourceFile(false), + _sourceFileExtension(defaultSourceFileExtension), + _sourceFileHeader(""), + _maxDepth(2) +{ + +} + +ShaderCreator::~ShaderCreator() { + +} + +void ShaderCreator::createSourceFile(bool b) { + _createSourceFile = b; +} + +void ShaderCreator::sourceFileExtension(const std::string& extension) { + if(extension != "") { + _sourceFileExtension = extension; + } +} + +void ShaderCreator::sourceFileHeader(const std::string& header) { + _sourceFileHeader = header; +} + +ghoul::opengl::ProgramObject* ShaderCreator::buildShader( + const std::string& name, const std::string& vpath, const std::string& fpath, const std::string& gpath) +{ + std::string vsPath = absPath(vpath); + std::string fsPath = absPath(fpath); + std::string gsPath = absPath(gpath); + + if( ! FileSys.fileExists(vsPath)) + return nullptr; + if( ! FileSys.fileExists(fsPath)) + return nullptr; + if (gsPath != "" && !FileSys.fileExists(gsPath)) + return nullptr; + + if(_createSourceFile) { + _generateSource(vsPath); + _generateSource(fsPath); + + vsPath = _generateFilename(vsPath); + fsPath = _generateFilename(fsPath); + } + + ProgramObject* po = new ProgramObject(name); + ShaderObject* vs = new ShaderObject(vsType, vsPath, name + " Vertex"); + ShaderObject* fs = new ShaderObject(fsType, fsPath, name + " Fragment"); + po->attachObject(vs); + po->attachObject(fs); + + if (gsPath != "") { + _generateSource(gsPath); + gsPath = _generateFilename(gsPath); + ShaderObject* gs = new ShaderObject(gsType, gsPath, name + " Geometry"); + po->attachObject(gs); + } + + if ( po->compileShaderObjects() && po->linkProgramObject()) + return po; + + // unsuccessful compilation, cleanup and return nullptr + delete po; + po = nullptr; + return po; +} + +void ShaderCreator::_generateSource(const std::string& filename) { + std::string generatedSource = ""; + if(_sourceFileHeader != "") + generatedSource += separator + "// HEADER\n" + separator + _sourceFileHeader + "\n"; + generatedSource += _loadSource(filename); + + std::ofstream of(_generateFilename(filename)); + of << generatedSource; + of.close(); +} + +std::string ShaderCreator::_loadSource(const std::string& filename, unsigned int depth) { + std::string contents = "", line; + std::ifstream f(filename); + + // Pre-allocate memory so the return string doesn't have to resize too often + // f.seekg( 0, std::ios::end ); + // unsigned int fsize = f.tellg(); + // f.seekg( 0); + // contents.reserve(fsize*3); + // line.reserve(fsize*3); + + contents += "\n"; + contents += separator; + contents += "// Filename: " + filename + "\n"; + // contents += "// Size: " + std::to_string(fsize) + "\n"; + contents += separator; + if(depth > _maxDepth) { + contents += "// TOO DEEP"; + return contents; + } + + if( ! FileSys.fileExists(filename)){ + contents += "// FILE NOT FOUND\n"; + return contents; + } + + std::regex e1(R"(^\s*#include \"(.+)\"\s*)"); + std::regex e2(R"(^\s*#include <(.+)>\s*)"); + while(std::getline(f, line)) { + std::smatch m; + if(std::regex_search(line, m, e1)) { + using namespace ghoul::filesystem; + std::string includeFilename = m[1]; + File f(filename); + includeFilename = f.directoryName() + FileSystem::PathSeparator + includeFilename; + //includeFilename = filename.substr(0, filename.find_last_of("/")+1) + includeFilename; + line = _loadSource(includeFilename, depth + 1); + } else if(std::regex_search(line, m, e2)) { + std::string includeFilename = m[1]; + line = _loadSource(absPath(includeFilename), depth + 1); + } + + contents += line + "\n"; + } + f.close(); + + return contents; +} + +std::string ShaderCreator::_generateFilename(const std::string& filename) { + // If way of confirming and creating a directory this could be a good solution + // to avoid cluttering in folders + // if(_cacheFolder != "") { + // size_t delimiter = filename.find_last_of("/"); + // std::string file = filename.substr(delimiter+1, filename.length() - delimiter); + // std::string path = filename.substr(0, filename.find_last_of("/")); + + // return path + "/" + _cacheFolder + "/" + file + "." + _sourceFileExtension; + // } + + return filename + "." + _sourceFileExtension; +} + +} \ No newline at end of file diff --git a/src/util/spice.cpp b/src/util/spice.cpp index 3be4c9a323..e7f8dc17fc 100644 --- a/src/util/spice.cpp +++ b/src/util/spice.cpp @@ -128,7 +128,7 @@ bool Spice::spk_getPosition(const std::string &target, const std::string &origin assert(this_); assert(Time::ref().isInitialized()); - SpiceDouble et = Time::ref().getTime(); + SpiceDouble et = Time::ref().currentTime(); SpiceDouble lt; spkpos_c(target.c_str(), et, "J2000", "LT+S", origin.c_str(), state, <); int failed = failed_c(); @@ -143,7 +143,7 @@ void Spice::spk_getPosition(int target, int origin, double state[3]) { assert(this_); assert(Time::ref().isInitialized()); - SpiceDouble et = Time::ref().getTime(); + SpiceDouble et = Time::ref().currentTime(); SpiceDouble lt; spkezp_c (target, et, "J2000", "NONE", origin, state, <); } @@ -156,7 +156,7 @@ bool Spice::spk_getOrientation(const std::string &target, double state[3][3]) { // ghoul logging std::string _loggerCat = "Spice::spk_getOrientation"; - SpiceDouble et = Time::ref().getTime(); + SpiceDouble et = Time::ref().currentTime(); std::string newname = "IAU_"; newname += target; pxform_c ( "J2000", newname.c_str(), et, state ); diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index 18302d4002..b4c5ff4278 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -21,9 +21,11 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ + #include #include #include +#include #ifdef WIN32 #include @@ -31,6 +33,7 @@ #include "openspace/util/spicemanager.h" #include "ghoul/filesystem/filesystem.h" +#include "ghoul/logging/logmanager.h" namespace { const std::string _loggerCat = "SpiceManager"; @@ -67,7 +70,7 @@ int SpiceManager::loadKernel(const std::string& fullPath, const std::string& sho std::string currentDirectory = FileSys.currentDirectory(); std::string::size_type last = fullPath.find_last_of(ghoul::filesystem::FileSystem::PathSeparator); if (last == std::string::npos) - return false; + return 0; std::string kernelDir = fullPath.substr(0, last); FileSys.setCurrentDirectory(kernelDir); furnsh_c(fullPath.c_str()); @@ -206,12 +209,32 @@ bool SpiceManager::getValueFromID(const std::string& bodyname, return true; } -double SpiceManager::stringToEphemerisTime(const std::string& epochString) const{ +double SpiceManager::convertStringToTdbSeconds(const std::string& epochString) const{ double et; str2et_c(epochString.c_str(), &et); return et; } +std::string SpiceManager::convertTdbSecondsToString(double seconds, + const std::string& format) const +{ + const int bufferSize = 128; + SpiceChar buffer[bufferSize]; + timout_c(seconds, format.c_str(), bufferSize - 1, buffer); + + int failed = failed_c(); + if (failed) { + char msg[1024]; + getmsg_c("LONG", 1024, msg); + //LERROR("Error retrieving position of target '" + target + "'"); + LERROR("Spice reported: " + std::string(msg)); + reset_c(); + return ""; + } + + return std::string(buffer); +} + bool SpiceManager::getTargetPosition(const std::string& target, double ephemerisTime, const std::string& referenceFrame, @@ -223,10 +246,18 @@ bool SpiceManager::getTargetPosition(const std::string& target, //method to put error out... spkpos_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), aberrationCorrection.c_str(), observer.c_str(), pos, &lightTime); - - if (pos[0] == NULL || pos[1] == NULL || pos[2] == NULL) - return false; + + int failed = failed_c(); + if(failed) { + char msg[1024]; + getmsg_c ( "LONG", 1024, msg ); + LERROR("Error retrieving position of target '" + target + "'"); + LERROR("Spice reported: " + std::string(msg)); + reset_c(); + return false; + } + memcpy(&targetPosition, pos, sizeof(double)* 3); return true; @@ -244,11 +275,18 @@ bool SpiceManager::getTargetState(const std::string& target, spkezr_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), aberrationCorrection.c_str(), observer.c_str(), state, &lightTime); + + int failed = failed_c(); + if(failed) { + char msg[1024]; + getmsg_c ( "LONG", 1024, msg ); + LERROR("Error retrieving state of target '" + target + "'"); + LERROR("Spice reported: " + std::string(msg)); + reset_c(); + return false; + } for (int i = 0; i < 3; i++){ - if (state[i] == NULL || state[i + 3] == NULL){ - return false; - } memcpy(&targetPosition, state , sizeof(double)* 3); memcpy(&targetVelocity, state +3, sizeof(double)* 3); } @@ -281,7 +319,6 @@ bool SpiceManager::getFieldOfView(const std::string& naifInstrumentId, double boresightVector[], std::vector& bounds, int& nrReturned) const{ - int n; int found; int naifId; int maxVectors = 12; diff --git a/src/util/time.cpp b/src/util/time.cpp index d515affa5a..dad1f20f43 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -1,62 +1,253 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ -// open space includes #include + +#include #include +#include +#include -// std includes -#include - -// spice includes -#include "SpiceUsr.h" #include +#include +#include + +namespace { + const std::string _loggerCat = "Time"; +} + namespace openspace { -Time* Time::this_ = nullptr; +namespace luascriptfunctions { -Time::Time() { - time_ = 0.0; +/** + * \ingroup LuaScripts + * setDeltaTime(number): + * Sets the delta time by calling the Time::setDeltaTime method + */ +int time_setDeltaTime(lua_State* L) { + const bool isFunction = (lua_isfunction(L, -1) != 0); + if (isFunction) { + // If the top of the stack is a function, it is ourself + const char* msg = lua_pushfstring(L, "method called without argument"); + return luaL_error(L, "bad argument (%s)", msg); + } - // load spice time kernel - furnsh_c (absPath("${OPENSPACE_DATA}/spice/naif0010.tls").c_str()); - - // convert UTC to ET - str2et_c ( "2006 JAN 31 01:00", &time_ ); -} - -Time::~Time() { + const bool isNumber = (lua_isnumber(L, -1) != 0); + if (isNumber) { + double value = lua_tonumber(L, -1); + openspace::Time::ref().setDeltaTime(value); + return 0; + } + else { + const char* msg = lua_pushfstring(L, "%s expected, got %s", + lua_typename(L, LUA_TNUMBER), luaL_typename(L, -1)); + return luaL_error(L, "bad argument #%d (%s)", 1, msg); + } } -void Time::init() { - assert( this_ == nullptr); - this_ = new Time(); +/** + * \ingroup LuaScripts + * deltaTime(): + * Returns the delta time by calling the Time::deltaTime method + */ +int time_deltaTime(lua_State* L) { + lua_pushnumber(L, openspace::Time::ref().deltaTime()); + return 1; } -void Time::deinit() { - assert(this_); - delete this_; - this_ = nullptr; +/** + * \ingroup LuaScripts + * setTime({number, string}): + * Sets the simulation time to the passed value. If the parameter is a number, it is + * interpreted as the number of seconds past the J2000 epoch and the + * Time::setTime(double) method is called. If the parameter is a string, it is + * interpreted as a structured date string and the Time::setTime(std::string) method + * is called + */ +int time_setTime(lua_State* L) { + const bool isFunction = (lua_isfunction(L, -1) != 0); + if (isFunction) { + // If the top of the stack is a function, it is ourself + const char* msg = lua_pushfstring(L, "method called without argument"); + return luaL_error(L, "bad argument (%s)", 1, msg); + } + + const bool isNumber = (lua_isnumber(L, -1) != 0); + const bool isString = (lua_isstring(L, -1) != 0); + if (!isNumber && !isString) { + const char* msg = lua_pushfstring(L, "%s or %s expected, got %s", + lua_typename(L, LUA_TNUMBER), + lua_typename(L, LUA_TSTRING), luaL_typename(L, -1)); + return luaL_error(L, "bad argument #%d (%s)", 1, msg); + } + if (isNumber) { + double value = lua_tonumber(L, -1); + openspace::Time::ref().setTime(value); + return 0; + } + if (isString) { + const char* time = lua_tostring(L, -1); + openspace::Time::ref().setTime(time); + return 0; + } + return 0; +} + +/** + * \ingroup LuaScripts + * currentTime(): + * Returns the current simulation time as the number of seconds past the J2000 epoch. + * It is returned by calling the Time::currentTime method. + */ +int time_currentTime(lua_State* L) { + lua_pushnumber(L, openspace::Time::ref().currentTime()); + return 1; +} + +/** + * \ingroup LuaScripts + * currentTimeUTC(): + * Returns the current simulation time as a structured ISO 8601 string using the UTC + * timezone by calling the Time::currentTimeUTC method + */ +int time_currentTimeUTC(lua_State* L) { + lua_pushstring(L, openspace::Time::ref().currentTimeUTC().c_str()); + return 1; +} + +} // namespace luascriptfunctions + + +Time* Time::_instance = nullptr; + +Time::Time() + : _time(-1.0) + , _deltaTimePerSecond(1.0) +{ +} + +bool Time::initialize(const std::string& lskKernel) { + assert( _instance == nullptr); + + if (!lskKernel.empty()) { + const int success = SpiceManager::ref().loadKernel( + absPath(lskKernel), "TimeKernel"); + if (success == 0) { + LERROR("Error loading SPICE time kernel '" << lskKernel << "'"); + return false; + } + } + _instance = new Time(); + return true; +} + +void Time::deinitialize() { + assert(_instance); + delete _instance; + _instance = nullptr; } Time& Time::ref() { - assert(this_); - return *this_; + assert(_instance); + return *_instance; } bool Time::isInitialized() { - return this_ != nullptr; + return (_instance != nullptr); } -void Time::setTime(const char* stringTime) { - assert(this_); - // convert UTC to ET - str2et_c ( stringTime, &time_ ); +void Time::setTime(double value) { + _time = std::move(value); } -double Time::getTime() { - assert(this_); - return time_; +double Time::currentTime() const { + assert(_instance); + return _time; +} + +double Time::advanceTime(double tickTime) { + return _time += _deltaTimePerSecond * tickTime; +} + +void Time::setDeltaTime(double deltaT) { + _deltaTimePerSecond = std::move(deltaT); +} + +double Time::deltaTime() const { + return _deltaTimePerSecond; +} + +void Time::setTime(std::string time) { + _time = SpiceManager::ref().convertStringToTdbSeconds(std::move(time)); +} + +std::string Time::currentTimeUTC() const { + return SpiceManager::ref().convertTdbSecondsToString(_time, "YYYY-MM-DDTHR:MN:SC.#####"); +} + +scripting::ScriptEngine::LuaLibrary Time::luaLibrary() { + scripting::ScriptEngine::LuaLibrary timeLibrary = { + "time", + { + { + "setDeltaTime", + &luascriptfunctions::time_setDeltaTime, + "setDeltaTime(number): Sets the amount of simulation time that happens " + "in one second of real time" + }, + { + "deltaTime", + &luascriptfunctions::time_deltaTime, + "deltaTime: Returns the amount of simulated time that passes in one " + "second of real time" + }, + { + "setTime", + &luascriptfunctions::time_setTime, + "setTime({number, string}): Sets the current simulation time to the " + "specified value. If the parameter is a number, the value is the number " + "of seconds past the J2000 epoch. If it is a string, it has to be a " + "valid ISO 8601 date string (YYYY-MM-DDTHH:MN:SS)" + }, + { + "currentTime", + &luascriptfunctions::time_currentTime, + "currentTime(): Returns the current time as the number of seconds since " + "the J2000 epoch" + }, + { + "currentTimeUTC", + &luascriptfunctions::time_currentTimeUTC, + "currentTimeUTC: Returns the current time as an ISO 8601 date string " + "(YYYY-MM-DDTHH:MN:SS" + } + } + }; + return std::move(timeLibrary); } } // namespace openspace