summaryrefslogtreecommitdiffstats
path: root/src/datavis3d
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavis3d')
-rw-r--r--src/datavis3d/Doxyfile1196
-rw-r--r--src/datavis3d/Mainpage.dox96
-rw-r--r--src/datavis3d/common.pri7
-rw-r--r--src/datavis3d/datavis3d.pro22
-rw-r--r--src/datavis3d/doc/qtdatavis3d.qdocconf47
-rw-r--r--src/datavis3d/documentationGroups.dox150
-rw-r--r--src/datavis3d/engine/drawer.cpp300
-rw-r--r--src/datavis3d/engine/drawer_p.h106
-rw-r--r--src/datavis3d/engine/engine.pri27
-rw-r--r--src/datavis3d/engine/engine.qrc38
-rw-r--r--src/datavis3d/engine/labelitem.cpp76
-rw-r--r--src/datavis3d/engine/labelitem_p.h79
-rw-r--r--src/datavis3d/engine/meshes/backgroudFlat.obj32
-rw-r--r--src/datavis3d/engine/meshes/backgroudSmooth.obj36
-rw-r--r--src/datavis3d/engine/meshes/coneFlat.obj89
-rw-r--r--src/datavis3d/engine/meshes/coneSmooth.obj90
-rw-r--r--src/datavis3d/engine/meshes/cubeFlat.obj47
-rw-r--r--src/datavis3d/engine/meshes/cubeSmooth.obj50
-rw-r--r--src/datavis3d/engine/meshes/cylinderFlat.obj299
-rw-r--r--src/datavis3d/engine/meshes/cylinderSmooth.obj330
-rw-r--r--src/datavis3d/engine/meshes/plane.obj15
-rw-r--r--src/datavis3d/engine/meshes/pyramidFlat.obj22
-rw-r--r--src/datavis3d/engine/meshes/pyramidSmooth.obj23
-rw-r--r--src/datavis3d/engine/meshes/sphere.obj1301
-rw-r--r--src/datavis3d/engine/meshes/sphereSmooth.obj1232
-rw-r--r--src/datavis3d/engine/q3dbars.cpp2105
-rw-r--r--src/datavis3d/engine/q3dbars.h167
-rw-r--r--src/datavis3d/engine/q3dbars_p.h180
-rw-r--r--src/datavis3d/engine/q3dmaps.cpp1525
-rw-r--r--src/datavis3d/engine/q3dmaps.h166
-rw-r--r--src/datavis3d/engine/q3dmaps_p.h171
-rw-r--r--src/datavis3d/engine/q3dwindow.cpp169
-rw-r--r--src/datavis3d/engine/q3dwindow.h86
-rw-r--r--src/datavis3d/engine/q3dwindow_p.h81
-rw-r--r--src/datavis3d/engine/qdataitem.cpp158
-rw-r--r--src/datavis3d/engine/qdataitem.h81
-rw-r--r--src/datavis3d/engine/qdataitem_p.h101
-rw-r--r--src/datavis3d/engine/qdatarow.cpp150
-rw-r--r--src/datavis3d/engine/qdatarow.h74
-rw-r--r--src/datavis3d/engine/qdatarow_p.h91
-rw-r--r--src/datavis3d/engine/qdataset.cpp271
-rw-r--r--src/datavis3d/engine/qdataset.h80
-rw-r--r--src/datavis3d/engine/qdataset_p.h107
-rw-r--r--src/datavis3d/engine/shaders/fragmentDepthTest7
-rw-r--r--src/datavis3d/engine/shaders/fragmentShader36
-rw-r--r--src/datavis3d/engine/shaders/fragmentShaderAmbient32
-rw-r--r--src/datavis3d/engine/shaders/fragmentShaderColorOnY33
-rw-r--r--src/datavis3d/engine/shaders/fragmentShaderDepth3
-rw-r--r--src/datavis3d/engine/shaders/fragmentShaderLabel8
-rw-r--r--src/datavis3d/engine/shaders/fragmentShaderSelection7
-rw-r--r--src/datavis3d/engine/shaders/fragmentShaderTexture35
-rw-r--r--src/datavis3d/engine/shaders/fragmentShadow140
-rw-r--r--src/datavis3d/engine/shaders/fragmentShadowNoTex147
-rw-r--r--src/datavis3d/engine/shaders/fragmentShadowNoTexColorOnY128
-rw-r--r--src/datavis3d/engine/shaders/vertexDepthTest9
-rw-r--r--src/datavis3d/engine/shaders/vertexShader28
-rw-r--r--src/datavis3d/engine/shaders/vertexShaderDepth8
-rw-r--r--src/datavis3d/engine/shaders/vertexShaderLabel11
-rw-r--r--src/datavis3d/engine/shaders/vertexShaderSelection7
-rw-r--r--src/datavis3d/engine/shaders/vertexShaderTexture26
-rw-r--r--src/datavis3d/engine/shaders/vertexShadow37
-rw-r--r--src/datavis3d/engine/theme.cpp298
-rw-r--r--src/datavis3d/engine/theme_p.h97
-rw-r--r--src/datavis3d/global/global.pri5
-rw-r--r--src/datavis3d/global/qdatavis3dglobal.h90
-rw-r--r--src/datavis3d/global/qdatavis3namespace.h141
-rw-r--r--src/datavis3d/utils/camerahelper.cpp281
-rw-r--r--src/datavis3d/utils/camerahelper_p.h93
-rw-r--r--src/datavis3d/utils/meshloader.cpp148
-rw-r--r--src/datavis3d/utils/meshloader_p.h74
-rw-r--r--src/datavis3d/utils/objecthelper.cpp165
-rw-r--r--src/datavis3d/utils/objecthelper_p.h91
-rw-r--r--src/datavis3d/utils/shaderhelper.cpp252
-rw-r--r--src/datavis3d/utils/shaderhelper_p.h133
-rw-r--r--src/datavis3d/utils/texturehelper.cpp358
-rw-r--r--src/datavis3d/utils/texturehelper_p.h90
-rw-r--r--src/datavis3d/utils/utils.cpp226
-rw-r--r--src/datavis3d/utils/utils.pri15
-rw-r--r--src/datavis3d/utils/utils_p.h84
-rw-r--r--src/datavis3d/utils/vertexindexer.cpp176
-rw-r--r--src/datavis3d/utils/vertexindexer_p.h111
81 files changed, 15103 insertions, 0 deletions
diff --git a/src/datavis3d/Doxyfile b/src/datavis3d/Doxyfile
new file mode 100644
index 00000000..e5d78895
--- /dev/null
+++ b/src/datavis3d/Doxyfile
@@ -0,0 +1,1196 @@
+# Doxyfile 1.4.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = QtDataVis3D
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = internal-docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# 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 =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = yes
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = YES
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is YES.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+# Having it set to not, output a lot of status messages to stdout, we still
+# get the warning into the log file
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE = internal-docs/doxygen.log
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = . ../../tests/auto/xmlpatternsxqts/ ../../tests/auto/xmlpatternsview
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+
+FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.dox *.gperf
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+# The Qt API uses qdoc and Doxygen doesn't like its tags, so exclude the q* files.
+EXCLUDE_PATTERNS = *.moc *.moc.cpp moc_*.cpp ui_*.h
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = YES
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT =
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = Q_SLOTS="slots" \
+ Q_SIGNALS="signals"
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+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 = YES
+
+CALLER_GRAPH = NO
+
+# 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
+# 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 = YES
+
+# 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 tags 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 GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will 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 png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# 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 = schema/doc/
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# 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 = YES
+
+# 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 = YES
+
+# 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
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/src/datavis3d/Mainpage.dox b/src/datavis3d/Mainpage.dox
new file mode 100644
index 00000000..973bc46f
--- /dev/null
+++ b/src/datavis3d/Mainpage.dox
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtXmlPatterns module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+/**
+ * @mainpage QtXmlPatterns -- an implementation of XML technologies
+ *
+ * - @ref Patternist_info
+ * - @ref Patternist_writingDoxygen
+ *
+ * @section Patternist_info Overview
+ *
+ * This is the internal developer documentation for QtXmlPatterns. Please refer
+ * to Qt Assistant for usage documentation.
+ *
+ * The documentation that you are reading right now, can be generated by
+ * running <tt>doxygen</tt> in this directory without arguments. The generated
+ * documentation can subsequently be browsed from
+ * <tt>internal-docs/html/index.html</tt>.
+ *
+ * @subsection Patternist_writingDoxygen Doxygen Conventions
+ *
+ * Doxygen conventions, are as follows.
+ *
+ * - <tt>@@returns</tt> and <tt>@@param</tt> paragraphs are terminated with a period.
+ * - When XPath or XQuery expressions/queries appears in the Doxygen comments, wrap them
+ * in the @c tt HTML tag.
+ * - Classes and free standing functions should have an <tt>@@author</tt> tag, specifying who
+ * is the main author of it.
+ * - No code examples should appear directly in the Doxygen comments, they should be included with
+ * <tt>@@include</tt> or <tt>@@dontinclude</tt>.
+ * - The following terms are marked with <tt>@@c</tt> or the @c tt HTML tag:
+ * - @c NaN
+ * - @c true and @c false, when referred to as boolean values
+ * - All QNames and item types. For example, <tt>item\()</tt> and <tt>xs:string</tt>. Remember
+ * to use the @c tt HTML tag in these cases in order to include non-trivial characters
+ * such as paranteses
+ * - @c null
+ * - @c stderr, @c stdout, and @c stdin
+ *
+ *
+ * The current Doxygen comments does in some cases not adhere to this, but the
+ * idea is to harmonize in that direction over time.
+ *
+ * PatternistSDK, located in the test sources, is documented in the
+ * PatternistSDK Doxygen module.
+ *
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
diff --git a/src/datavis3d/common.pri b/src/datavis3d/common.pri
new file mode 100644
index 00000000..8532fc77
--- /dev/null
+++ b/src/datavis3d/common.pri
@@ -0,0 +1,7 @@
+# This qmake file is included by all Patternist projects and contains common Qt defines,
+# compiler warnings, and include paths.
+
+INCLUDEPATH += $$PWD/engine \
+ $$PWD/global \
+ $$PWD/utils
+
diff --git a/src/datavis3d/datavis3d.pro b/src/datavis3d/datavis3d.pro
new file mode 100644
index 00000000..b4169c4e
--- /dev/null
+++ b/src/datavis3d/datavis3d.pro
@@ -0,0 +1,22 @@
+TARGET = QtDataVis3D
+QT = core gui opengl #qml
+
+DEFINES += QTCOMMERCIALDATAVIS3D_LIBRARY
+
+QMAKE_DOCS = $$PWD/doc/qtdatavis3d.qdocconf
+
+load(qt_module)
+
+include($$PWD/common.pri)
+include($$PWD/engine/engine.pri)
+include($$PWD/global/global.pri)
+include($$PWD/utils/utils.pri)
+
+wince* {
+ # The Microsoft MIPS compiler crashes if /Og is specified.
+ # -O2/1 expands to /Og plus additional arguments.
+ contains(DEFINES, MIPS) {
+ QMAKE_CXXFLAGS_RELEASE ~= s/-O2/-Oi -Ot -Oy -Ob2/
+ QMAKE_CXXFLAGS_RELEASE ~= s/-O1/-Os -Oy -Ob2/
+ }
+}
diff --git a/src/datavis3d/doc/qtdatavis3d.qdocconf b/src/datavis3d/doc/qtdatavis3d.qdocconf
new file mode 100644
index 00000000..c2c084b3
--- /dev/null
+++ b/src/datavis3d/doc/qtdatavis3d.qdocconf
@@ -0,0 +1,47 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+
+# Name of the project which must match the outputdir. Determines the .index file
+project = qtdatavis3d
+
+# Directories in which to search for files to document and images.
+# By default set to the root directory of the project for sources
+# and headers and qdoc will therefore generate output for each file.
+# Images should be placed in <rootdir>/dic/images and examples in
+# <rootdir>/examples.
+# Paths are relative to the location of this file.
+exampledirs += ../../../examples \
+ snippets
+
+headerdirs += ..
+imagedirs += images
+sourcedirs += ..
+
+depends += qtcore qtgui
+
+# The following parameters are for creating a qhp file, the qhelpgenerator
+# program can convert the qhp file into a qch file which can be opened in
+# Qt Assistant and/or Qt Creator.
+
+# Defines the name of the project. You cannot use operators (+, =, -) in
+# the name. Properties for this project are set using a qhp.<projectname>.property
+# format.
+qhp.projects = qtdatavis3d
+
+# Sets the name of the output qhp file.
+qhp.qtdatavis3d.file = qtdatavis3d.qhp
+
+# Namespace for the output file. This namespace is used to distinguish between
+# different documentation files in Creator/Assistant.
+qhp.qtdatavis3d.namespace = org.qt-project.qtdatavis3d.501
+
+# Title for the package, will be the main title for the package in
+# Assistant/Creator.
+qhp.qtdatavis3d.indexTitle = Qt Data Visualization 3D
+
+# Only update the name of the project for the next variables.
+qhp.qtdatavis3d.virtualFolder = qtdatavis3d
+qhp.qtdatavis3d.subprojects = classes
+qhp.qtdatavis3d.subprojects.classes.title = C++ Classes
+qhp.qtdatavis3d.subprojects.classes.indexTitle = Qt Data Visualization 3D C++ Classes
+qhp.qtdatavis3d.subprojects.classes.selectors = class fake:headerfile
+qhp.qtdatavis3d.subprojects.classes.sortPages = true
diff --git a/src/datavis3d/documentationGroups.dox b/src/datavis3d/documentationGroups.dox
new file mode 100644
index 00000000..ed9c3f1c
--- /dev/null
+++ b/src/datavis3d/documentationGroups.dox
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtXmlPatterns module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+/**
+ * @file
+ * @short Contains Doxygen documentation for groups.
+ */
+
+namespace QPatternist
+{
+ /**
+ * @short The abstract syntax tree nodes that implements the builtin
+ * functions, such as @c fn:concat().
+ *
+ * @defgroup Patternist_functions Function Implementations
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
+
+ /**
+ * @short The abstract syntax tree nodes that is generated for XPath,
+ * XQuery, and XSL-T code.
+ *
+ * XPath's approach of compilation is traditional. An Abstract Syntax
+ * Tree(AST) is built, where the Expression class is the abstract base
+ * class for all kinds of implementations of expressions.
+ *
+ * What perhaps can be said to be characteristic for Patternist is that the
+ * base class, Expression, performs a lot of work, and that sub-classes
+ * declares what specific behaviors they need, which the Expression's
+ * functions then bring into action.
+ *
+ * XPath expressions often have different amount of operands. For example,
+ * the 'and' expression takes two, the context item(".") none, and the
+ * if-expression three. To help expression implementations with that, there
+ * exist the abstract EmptyContainer, SingleContainer, PairContainer,
+ * TripleContainer, and UnlimitedContainer classes for avoiding duplicating
+ * code.
+ *
+ * @defgroup Patternist_expressions Expressions
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
+
+ /**
+ * @short Various classes that contains small utility functions.
+ *
+ * @defgroup Patternist Utility Classes
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
+
+ /**
+ * @short Classes for the type system in the XQuery & XSL-T language.
+ *
+ * @defgroup Patternist_types Type system
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
+
+ /**
+ * @defgroup Patternist_xdm XQuery/XPath Data Model
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
+
+ /**
+ * @short Patternist's family of iterators in one of the most central parts
+ * of Patternist's API, and are responsible for carrying, and typically
+ * also creating, data.
+ *
+ * An iterator, which always is an Iterator sub-class, is similar to a
+ * Java-style iterator. What signifies Patternist's iterators is that they
+ * almost always contains business logic(which is the cause to their
+ * efficiency).
+ *
+ * An example which illustrates this principle is the RangeIterator. When
+ * the RangeExpression is told to create a sequence of integers between 1
+ * and 1000, it doesn't enter a loop that allocates 1000 Integer instances,
+ * but instead return an RangeIterator that incrementally creates the
+ * numbers when asked to do so via its RangeIterator::next() function. If
+ * it turns out that the expression that has the range expression as
+ * operand only needs three items from it, that is what gets created, not
+ * 1000.
+ *
+ * All iterators operates by that principle, perhaps suitably labeled as
+ * "pull-based", "lazy loaded" or "serialized". Central for the XPath
+ * language is that it filters and selects data, and the iterators supports
+ * this well by letting the demand of the filter expressions(the callees)
+ * decide how "much" source that gets computed. In this way the evaluation
+ * of an expression tree can lead to a chain of pipelined iterators, where
+ * the first asks the second for data and then performs its specific
+ * operations, the second subsequently asks the third, and so forth.
+ *
+ * However, the iterators are not limited to be used for representing
+ * sequences of items in the XPath Data Model. The Iterator is
+ * parameterized on one argument, meaning any type of "units" can be
+ * iterated, be it Item or any other. One use of this is in the
+ * ExpressionSequence(which implements the comma operator) where it creates
+ * Iterator instances over Expression instances -- its operands. The
+ * parameterization is often used in combination with the MappingIterator
+ * and the MappingCallback.
+ *
+ * @defgroup Patternist_iterators Iterators
+ * @author Frans Englich <frans.englich@nokia.com>
+ */
+}
diff --git a/src/datavis3d/engine/drawer.cpp b/src/datavis3d/engine/drawer.cpp
new file mode 100644
index 00000000..722a54b8
--- /dev/null
+++ b/src/datavis3d/engine/drawer.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdatavis3namespace.h"
+#include "drawer_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "camerahelper_p.h"
+#include "qdataitem.h"
+#include "qdataitem_p.h"
+#include "utils_p.h"
+#include "texturehelper_p.h"
+#include <QMatrix4x4>
+#include <qmath.h>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+Drawer::Drawer(const Theme &theme, const QFont &font, LabelTransparency transparency)
+ : m_theme(theme),
+ m_font(font),
+ m_transparency(transparency),
+ m_textureHelper(new TextureHelper())
+{
+ initializeOpenGLFunctions();
+}
+
+Drawer::~Drawer()
+{
+
+}
+
+void Drawer::setTheme(const Theme &theme)
+{
+ m_theme = theme;
+ emit drawerChanged();
+}
+
+void Drawer::setFont(const QFont &font)
+{
+ m_font = font;
+ emit drawerChanged();
+}
+
+void Drawer::setTransparency(LabelTransparency transparency)
+{
+ m_transparency = transparency;
+ emit drawerChanged();
+}
+
+void Drawer::drawObject(ShaderHelper *shader, ObjectHelper *object, GLuint textureId,
+ GLuint depthTextureId)
+{
+ if (textureId) {
+ // Activate texture
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ shader->setUniformValue(shader->texture(), 0);
+ }
+
+ if (depthTextureId) {
+ // Activate depth texture
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, depthTextureId);
+ shader->setUniformValue(shader->shadow(), 1);
+ }
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(shader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->vertexBuf());
+ glVertexAttribPointer(shader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
+
+ // 2nd attribute buffer : normals
+ glEnableVertexAttribArray(shader->normalAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->normalBuf());
+ glVertexAttribPointer(shader->normalAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
+
+ if (textureId || depthTextureId) {
+ // 3rd attribute buffer : UVs
+ glEnableVertexAttribArray(shader->uvAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, object->uvBuf());
+ glVertexAttribPointer(shader->uvAtt(), 2, GL_FLOAT, GL_FALSE, 0, (void*)0);
+ }
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, object->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, object->indexCount(), GL_UNSIGNED_SHORT, (void*)0);
+
+ // Free buffers
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ if (textureId || depthTextureId) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisableVertexAttribArray(shader->uvAtt());
+ }
+ glDisableVertexAttribArray(shader->normalAtt());
+ glDisableVertexAttribArray(shader->posAtt());
+}
+
+void Drawer::drawLabel(const QDataItem &item, const LabelItem &label,
+ const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix,
+ const QVector3D &positionComp, const QVector3D &rotation,
+ GLfloat maxHeight, SelectionMode mode,
+ ShaderHelper *shader, ObjectHelper *object, bool useDepth, bool rotateAlong,
+ LabelPosition position, Qt::AlignmentFlag alignment)
+{
+ // Draw label
+ LabelItem labelItem = label;
+ if (!labelItem.textureId())
+ return; // No texture, skip
+
+ QSize textureSize = labelItem.size();
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ GLfloat xPosition;
+ GLfloat yPosition;
+ GLfloat zPosition = positionComp.z();
+
+ switch (position) {
+ case LabelBelow: {
+ yPosition = -1.6f; // minus maximum negative height (+ some extra for label)
+ break;
+ }
+ case LabelLow: {
+ yPosition = -positionComp.y();
+ break;
+ }
+ case LabelMid: {
+ // Use this for positioning with absolute item y position value
+ yPosition = item.d_ptr->translation().y();
+ break;
+ }
+ case LabelHigh: {
+ // TODO: Fix this. Can't seem to get it right (if ok with positive-only bars, doesn't look good on +- and vice versa)
+ yPosition = item.d_ptr->translation().y() + (item.d_ptr->value() / maxHeight) / 2.0f;
+ break;
+ }
+ case LabelOver: {
+ float mod = 0.1f;
+ if (item.d_ptr->value() < 0)
+ mod = -0.1f;
+ yPosition = item.d_ptr->translation().y() - (positionComp.y() / 2.0f - 0.2f)
+ + (item.d_ptr->value() / maxHeight) + mod;
+ break;
+ }
+ case LabelBottom: {
+ yPosition = -1.95f; // TODO: Calculate from scene
+ xPosition = 0.0f;
+ break;
+ }
+ case LabelTop: {
+ yPosition = 1.95f; // TODO: Calculate from scene
+ xPosition = 0.0f;
+ break;
+ }
+ case LabelLeft: {
+ yPosition = 0.0f;
+ xPosition = -2.5f; // TODO: Calculate from scene
+ break;
+ }
+ case LabelRight: {
+ yPosition = 0.0f;
+ xPosition = 2.5f; // TODO: Calculate from scene
+ break;
+ }
+ }
+
+ // Calculate scale factor to get uniform font size
+ GLfloat scaledFontSize = 0.05f + m_font.pointSizeF() / 500.0f;
+ GLfloat scaleFactor = scaledFontSize / (GLfloat)textureSize.height();
+
+ // Apply alignment
+ GLfloat xAlignment = 0.0f;
+ GLfloat zAlignment = 0.0f;
+ switch (alignment) {
+ case Qt::AlignLeft: {
+ xAlignment = (-(GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(cos(rotation.y() * m_pi / 180.0f));
+ zAlignment = ((GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(sin(rotation.y() * m_pi / 180.0f));
+ break;
+ }
+ case Qt::AlignRight: {
+ xAlignment = ((GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(cos(rotation.y() * m_pi / 180.0f));
+ zAlignment = (-(GLfloat)textureSize.width() * scaleFactor)
+ * qFabs(sin(rotation.y() * m_pi / 180.0f));
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (position < LabelBottom) {
+ xPosition = item.d_ptr->translation().x();
+ if (useDepth)
+ zPosition = item.d_ptr->translation().z();
+ else if (ModeZoomColumn == mode)
+ xPosition = -(item.d_ptr->translation().z()) + positionComp.z(); // flip first to left
+ }
+
+ // Position label
+ modelMatrix.translate(xPosition + xAlignment, yPosition, zPosition + zAlignment);
+
+ // Rotate
+ modelMatrix.rotate(rotation.z(), 0.0f, 0.0f, 1.0f);
+ modelMatrix.rotate(rotation.y(), 0.0f, 1.0f, 0.0f);
+ modelMatrix.rotate(rotation.x(), 1.0f, 0.0f, 0.0f);
+
+ if (useDepth && !rotateAlong) {
+ // Apply negative camera rotations to keep labels facing camera
+ QPointF camRotations = CameraHelper::getCameraRotations();
+ modelMatrix.rotate(-camRotations.x(), 0.0f, 1.0f, 0.0f);
+ modelMatrix.rotate(-camRotations.y(), 1.0f, 0.0f, 0.0f);
+ }
+
+ // Scale label based on text size
+ modelMatrix.scale(QVector3D((GLfloat)textureSize.width() * scaleFactor,
+ scaledFontSize,
+ 0.0f));
+
+ MVPMatrix = projectionmatrix * viewmatrix * modelMatrix;
+
+ // Set shader bindings
+ shader->setUniformValue(shader->MVP(), MVPMatrix);
+
+ // Draw the object
+ drawObject(shader, object, labelItem.textureId());
+}
+
+void Drawer::generateLabelTexture(QDataItem *item)
+{
+ LabelItem labelItem = item->d_ptr->label();
+ generateLabelItem(&labelItem, item->d_ptr->valueStr());
+ item->d_ptr->setLabel(labelItem);
+}
+
+void Drawer::generateLabelItem(LabelItem *item, const QString &text)
+{
+ // Delete previous texture, if there is one
+ GLuint labelTexture = item->textureId();
+ if (labelTexture)
+ glDeleteTextures(1, &labelTexture);
+
+ // Create labels
+ // Print label into a QImage using QPainter
+ QImage label = Utils::printTextToImage(m_font,
+ text,
+ m_theme.m_textBackgroundColor,
+ m_theme.m_textColor,
+ m_transparency);
+
+ // Set label size
+ item->setSize(label.size());
+ // Insert text texture into label
+ item->setTextureId(m_textureHelper->create2DTexture(label, true, true));
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/drawer_p.h b/src/datavis3d/engine/drawer_p.h
new file mode 100644
index 00000000..3b6a2c49
--- /dev/null
+++ b/src/datavis3d/engine/drawer_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef DRAWER_P_H
+#define DRAWER_P_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+#include "QtDataVis3D/qdatavis3namespace.h"
+#include "q3dbars.h"
+#include "theme_p.h"
+#include "labelitem_p.h"
+#include <QFont>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class QDataItem;
+class ShaderHelper;
+class ObjectHelper;
+class TextureHelper;
+
+class Drawer : public QObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ explicit Drawer(const Theme &theme, const QFont &font, LabelTransparency transparency);
+ ~Drawer();
+
+ void setTheme(const Theme &theme);
+ void setFont(const QFont &font);
+ void setTransparency(LabelTransparency transparency);
+
+ void drawObject(ShaderHelper *shader, ObjectHelper *object, GLuint textureId = 0,
+ GLuint depthTextureId = 0);
+ void drawLabel(const QDataItem &item, const LabelItem &label,
+ const QMatrix4x4 &viewmatrix, const QMatrix4x4 &projectionmatrix,
+ const QVector3D &positionComp, const QVector3D &rotation, GLfloat maxHeight,
+ SelectionMode mode, ShaderHelper *shader, ObjectHelper *object,
+ bool useDepth = false, bool rotateAlong = false,
+ LabelPosition position = LabelOver,
+ Qt::AlignmentFlag alignment = Qt::AlignCenter);
+
+ void generateLabelTexture(QDataItem *item);
+ void generateLabelItem(LabelItem *item, const QString &text);
+
+Q_SIGNALS:
+ void drawerChanged();
+
+private:
+ Theme m_theme;
+ QFont m_font;
+ LabelTransparency m_transparency;
+ TextureHelper *m_textureHelper;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/engine.pri b/src/datavis3d/engine/engine.pri
new file mode 100644
index 00000000..ba063186
--- /dev/null
+++ b/src/datavis3d/engine/engine.pri
@@ -0,0 +1,27 @@
+SOURCES += $$PWD/q3dwindow.cpp \
+ $$PWD/q3dbars.cpp \
+ $$PWD/q3dmaps.cpp \
+ $$PWD/qdataitem.cpp \
+ $$PWD/qdatarow.cpp \
+ $$PWD/qdataset.cpp \
+ $$PWD/theme.cpp \
+ $$PWD/drawer.cpp \
+ $$PWD/labelitem.cpp
+
+HEADERS += $$PWD/q3dwindow_p.h \
+ $$PWD/q3dwindow.h \
+ $$PWD/q3dbars.h \
+ $$PWD/q3dbars_p.h \
+ $$PWD/q3dmaps.h \
+ $$PWD/q3dmaps_p.h \
+ $$PWD/qdataitem.h \
+ $$PWD/qdataitem_p.h \
+ $$PWD/qdatarow.h \
+ $$PWD/qdatarow_p.h \
+ $$PWD/qdataset.h \
+ $$PWD/qdataset_p.h \
+ $$PWD/theme_p.h \
+ $$PWD/drawer_p.h \
+ $$PWD/labelitem_p.h
+
+RESOURCES += engine/engine.qrc
diff --git a/src/datavis3d/engine/engine.qrc b/src/datavis3d/engine/engine.qrc
new file mode 100644
index 00000000..beff232d
--- /dev/null
+++ b/src/datavis3d/engine/engine.qrc
@@ -0,0 +1,38 @@
+<RCC>
+ <qresource prefix="/defaultMeshes">
+ <file alias="cone">meshes/coneFlat.obj</file>
+ <file alias="coneSmooth">meshes/coneSmooth.obj</file>
+ <file alias="pyramid">meshes/pyramidFlat.obj</file>
+ <file alias="pyramidSmooth">meshes/pyramidSmooth.obj</file>
+ <file alias="bar">meshes/cubeFlat.obj</file>
+ <file alias="barSmooth">meshes/cubeSmooth.obj</file>
+ <file alias="cylinder">meshes/cylinderFlat.obj</file>
+ <file alias="cylinderSmooth">meshes/cylinderSmooth.obj</file>
+ <file alias="background">meshes/backgroudFlat.obj</file>
+ <file alias="backgroundSmooth">meshes/backgroudSmooth.obj</file>
+ <file alias="label">meshes/plane.obj</file>
+ <file alias="sphere">meshes/sphere.obj</file>
+ <file alias="sphereSmooth">meshes/sphereSmooth.obj</file>
+ </qresource>
+ <qresource prefix="/shaders">
+ <file alias="fragment">shaders/fragmentShader</file>
+ <file alias="vertex">shaders/vertexShader</file>
+ <file alias="fragmentAmbient">shaders/fragmentShaderAmbient</file>
+ <file alias="fragmentColorOnY">shaders/fragmentShaderColorOnY</file>
+ <file alias="fragmentSelection">shaders/fragmentShaderSelection</file>
+ <file alias="vertexSelection">shaders/vertexShaderSelection</file>
+ <file alias="fragmentTexture">shaders/fragmentShaderTexture</file>
+ <file alias="vertexTexture">shaders/vertexShaderTexture</file>
+ <file alias="fragmentLabel">shaders/fragmentShaderLabel</file>
+ <file alias="vertexLabel">shaders/vertexShaderLabel</file>
+ <file alias="fragmentDepth">shaders/fragmentShaderDepth</file>
+ <file alias="vertexDepth">shaders/vertexShaderDepth</file>
+ <file alias="testDepthFrag">shaders/fragmentDepthTest</file>
+ <file alias="testDepthVert">shaders/vertexDepthTest</file>
+ <file alias="fragmentShadow">shaders/fragmentShadow</file>
+ <file alias="vertexShadow">shaders/vertexShadow</file>
+ <file alias="fragmentShadowNoTex">shaders/fragmentShadowNoTex</file>
+ <file alias="fragmentShadowNoTexColorOnY">shaders/fragmentShadowNoTexColorOnY</file>
+ </qresource>
+ <qresource prefix="/textures"/>
+</RCC>
diff --git a/src/datavis3d/engine/labelitem.cpp b/src/datavis3d/engine/labelitem.cpp
new file mode 100644
index 00000000..6ce0663c
--- /dev/null
+++ b/src/datavis3d/engine/labelitem.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "labelitem_p.h"
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+LabelItem::LabelItem()
+ : m_size(QSize(0, 0)),
+ m_textureId(0)
+{
+}
+
+LabelItem::~LabelItem()
+{
+}
+
+void LabelItem::setSize(const QSize &size)
+{
+ m_size = size;
+}
+
+QSize LabelItem::size()
+{
+ return m_size;
+}
+
+void LabelItem::setTextureId(GLuint textureId)
+{
+ m_textureId = textureId;
+}
+
+GLuint LabelItem::textureId()
+{
+ return m_textureId;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/labelitem_p.h b/src/datavis3d/engine/labelitem_p.h
new file mode 100644
index 00000000..49693631
--- /dev/null
+++ b/src/datavis3d/engine/labelitem_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef LABELITEM_P_H
+#define LABELITEM_P_H
+
+#include "qdatavis3dglobal.h"
+#include <QOpenGLFunctions>
+#include <QSize>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class LabelItem
+{
+public:
+ explicit LabelItem();
+ ~LabelItem();
+
+ void setSize(const QSize &size);
+ QSize size();
+ void setTextureId(GLuint textureId);
+ GLuint textureId();
+
+private:
+ QSize m_size;
+ GLuint m_textureId;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/meshes/backgroudFlat.obj b/src/datavis3d/engine/meshes/backgroudFlat.obj
new file mode 100644
index 00000000..cf4d10a5
--- /dev/null
+++ b/src/datavis3d/engine/meshes/backgroudFlat.obj
@@ -0,0 +1,32 @@
+# Blender v2.66 (sub 0) OBJ File: 'backgroud.blend'
+# www.blender.org
+o Cube
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 0.999999 1.000000 1.000001
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+vt 0.000000 0.501529
+vt 0.001529 1.000000
+vt 0.500000 0.998471
+vt 0.501529 0.500000
+vt 1.000000 0.498471
+vt 0.998471 0.000000
+vt 0.500000 0.498471
+vt 0.498471 0.000000
+vt 0.000000 0.001529
+vt 0.498471 0.500000
+vt 0.500000 0.001529
+vt 0.001529 0.500000
+vn -0.000000 1.000000 0.000000
+vn 0.000000 -0.000000 -1.000000
+vn 1.000000 0.000000 0.000000
+s off
+f 1/1/1 4/2/1 3/3/1
+f 2/4/2 3/5/2 6/6/2
+f 3/7/3 4/8/3 7/9/3
+f 2/10/1 1/1/1 3/3/1
+f 5/11/2 2/4/2 6/6/2
+f 6/12/3 3/7/3 7/9/3
diff --git a/src/datavis3d/engine/meshes/backgroudSmooth.obj b/src/datavis3d/engine/meshes/backgroudSmooth.obj
new file mode 100644
index 00000000..ad16d904
--- /dev/null
+++ b/src/datavis3d/engine/meshes/backgroudSmooth.obj
@@ -0,0 +1,36 @@
+# Blender v2.66 (sub 0) OBJ File: 'backgroud.blend'
+# www.blender.org
+o Cube
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 0.999999 1.000000 1.000001
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+vt 0.000000 0.501529
+vt 0.001529 1.000000
+vt 0.500000 0.998471
+vt 0.501529 0.500000
+vt 1.000000 0.498471
+vt 0.998471 0.000000
+vt 0.500000 0.498471
+vt 0.498471 0.000000
+vt 0.000000 0.001529
+vt 0.498471 0.500000
+vt 0.500000 0.001529
+vt 0.001529 0.500000
+vn 0.000000 0.999969 0.000000
+vn 0.707083 0.707083 0.000000
+vn 0.577349 0.577349 -0.577349
+vn 0.000000 0.707083 -0.707083
+vn 0.707083 0.000000 -0.707083
+vn 0.999969 0.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+s 1
+f 1/1/1 4/2/2 3/3/3
+f 2/4/4 3/5/3 6/6/5
+f 3/7/3 4/8/2 7/9/6
+f 2/10/4 1/1/1 3/3/3
+f 5/11/7 2/4/4 6/6/5
+f 6/12/5 3/7/3 7/9/6
diff --git a/src/datavis3d/engine/meshes/coneFlat.obj b/src/datavis3d/engine/meshes/coneFlat.obj
new file mode 100644
index 00000000..51c3821e
--- /dev/null
+++ b/src/datavis3d/engine/meshes/coneFlat.obj
@@ -0,0 +1,89 @@
+# Blender v2.66 (sub 0) OBJ File: 'cone.blend'
+# www.blender.org
+o Cone_Cone.001
+v 0.000000 -1.000000 -1.000000
+v 0.309017 -1.000000 -0.951057
+v 0.587785 -1.000000 -0.809017
+v 0.809017 -1.000000 -0.587785
+v 0.951057 -1.000000 -0.309017
+v 1.000000 -1.000000 0.000000
+v 0.951056 -1.000000 0.309017
+v 0.809017 -1.000000 0.587785
+v 0.000000 1.000000 0.000000
+v 0.587785 -1.000000 0.809017
+v 0.309017 -1.000000 0.951057
+v -0.000000 -1.000000 1.000000
+v -0.309017 -1.000000 0.951056
+v -0.587786 -1.000000 0.809017
+v -0.809017 -1.000000 0.587785
+v -0.951057 -1.000000 0.309016
+v -1.000000 -1.000000 -0.000001
+v -0.951056 -1.000000 -0.309018
+v -0.809016 -1.000000 -0.587786
+v -0.587784 -1.000000 -0.809018
+v -0.309016 -1.000000 -0.951057
+vt 0.018984 0.308330
+vt 0.500000 0.482045
+vt 0.000000 0.410924
+vt 0.011213 0.505476
+vt 0.051524 0.582730
+vt 0.116989 0.635124
+vt 0.066306 0.207736
+vt 0.137334 0.118990
+vt 0.225115 0.050777
+vt 0.321057 0.009776
+vt 0.415768 0.000000
+vt 0.499978 0.022406
+vt 0.551525 0.582730
+vt 1.000000 0.482045
+vt 0.616989 0.635125
+vt 0.511213 0.505476
+vt 0.500000 0.410924
+vt 0.518984 0.308330
+vt 0.566306 0.207736
+vt 0.637334 0.118990
+vt 0.725115 0.050777
+vt 0.821057 0.009776
+vt 0.915768 0.000000
+vt 0.999978 0.022406
+vn -0.407058 0.442793 -0.798898
+vn 0.140263 0.442793 -0.885585
+vn -0.140262 0.442793 -0.885585
+vn 0.407059 0.442793 -0.798898
+vn -0.634008 0.442793 -0.634010
+vn -0.798897 0.442793 -0.407060
+vn -0.885585 0.442793 -0.140264
+vn -0.885585 0.442793 0.140262
+vn -0.798898 0.442793 0.407058
+vn -0.634009 0.442793 0.634009
+vn -0.407059 0.442793 0.798898
+vn -0.140263 0.442793 0.885585
+vn 0.140263 0.442793 0.885585
+vn 0.407059 0.442793 0.798898
+vn 0.634009 0.442793 0.634009
+vn 0.798898 0.442793 0.407059
+vn 0.885585 0.442793 0.140263
+vn 0.885585 0.442793 -0.140263
+vn 0.798898 0.442793 -0.407059
+vn 0.634009 0.442793 -0.634009
+s off
+f 20/1/1 9/2/1 21/3/1
+f 1/4/2 9/2/2 2/5/2
+f 21/3/3 9/2/3 1/4/3
+f 2/5/4 9/2/4 3/6/4
+f 19/7/5 9/2/5 20/1/5
+f 18/8/6 9/2/6 19/7/6
+f 17/9/7 9/2/7 18/8/7
+f 16/10/8 9/2/8 17/9/8
+f 15/11/9 9/2/9 16/10/9
+f 14/12/10 9/2/10 15/11/10
+f 13/13/11 9/14/11 14/15/11
+f 12/16/12 9/14/12 13/13/12
+f 11/17/13 9/14/13 12/16/13
+f 10/18/14 9/14/14 11/17/14
+f 8/19/15 9/14/15 10/18/15
+f 7/20/16 9/14/16 8/19/16
+f 6/21/17 9/14/17 7/20/17
+f 5/22/18 9/14/18 6/21/18
+f 4/23/19 9/14/19 5/22/19
+f 3/24/20 9/14/20 4/23/20
diff --git a/src/datavis3d/engine/meshes/coneSmooth.obj b/src/datavis3d/engine/meshes/coneSmooth.obj
new file mode 100644
index 00000000..48c48ba8
--- /dev/null
+++ b/src/datavis3d/engine/meshes/coneSmooth.obj
@@ -0,0 +1,90 @@
+# Blender v2.66 (sub 0) OBJ File: 'cone.blend'
+# www.blender.org
+o Cone_Cone.001
+v 0.000000 -1.000000 -1.000000
+v 0.309017 -1.000000 -0.951057
+v 0.587785 -1.000000 -0.809017
+v 0.809017 -1.000000 -0.587785
+v 0.951057 -1.000000 -0.309017
+v 1.000000 -1.000000 0.000000
+v 0.951056 -1.000000 0.309017
+v 0.809017 -1.000000 0.587785
+v 0.000000 1.000000 0.000000
+v 0.587785 -1.000000 0.809017
+v 0.309017 -1.000000 0.951057
+v -0.000000 -1.000000 1.000000
+v -0.309017 -1.000000 0.951056
+v -0.587786 -1.000000 0.809017
+v -0.809017 -1.000000 0.587785
+v -0.951057 -1.000000 0.309016
+v -1.000000 -1.000000 -0.000001
+v -0.951056 -1.000000 -0.309018
+v -0.809016 -1.000000 -0.587786
+v -0.587784 -1.000000 -0.809018
+v -0.309016 -1.000000 -0.951057
+vt 0.018984 0.308330
+vt 0.500000 0.482045
+vt 0.000000 0.410924
+vt 0.011213 0.505476
+vt 0.051524 0.582730
+vt 0.116989 0.635124
+vt 0.066306 0.207736
+vt 0.137334 0.118990
+vt 0.225115 0.050777
+vt 0.321057 0.009776
+vt 0.415768 0.000000
+vt 0.499978 0.022406
+vt 0.551525 0.582730
+vt 1.000000 0.482045
+vt 0.616989 0.635125
+vt 0.511213 0.505476
+vt 0.500000 0.410924
+vt 0.518984 0.308330
+vt 0.566306 0.207736
+vt 0.637334 0.118990
+vt 0.725115 0.050777
+vt 0.821057 0.009776
+vt 0.915768 0.000000
+vt 0.999978 0.022406
+vn -0.525712 0.447188 -0.723594
+vn 0.000000 1.000000 0.000000
+vn -0.276376 0.447188 -0.850642
+vn 0.000000 0.447188 -0.894406
+vn 0.276376 0.447188 -0.850642
+vn 0.525712 0.447188 -0.723594
+vn -0.723594 0.447188 -0.525712
+vn -0.850642 0.447188 -0.276376
+vn -0.894406 0.447188 0.000000
+vn -0.850642 0.447188 0.276376
+vn -0.723594 0.447188 0.525712
+vn -0.525712 0.447188 0.723594
+vn -0.276376 0.447188 0.850642
+vn 0.000000 0.447188 0.894406
+vn 0.276376 0.447188 0.850642
+vn 0.525712 0.447188 0.723594
+vn 0.723594 0.447188 0.525712
+vn 0.850642 0.447188 0.276376
+vn 0.894406 0.447188 0.000000
+vn 0.850642 0.447188 -0.276376
+vn 0.723594 0.447188 -0.525712
+s 1
+f 20/1/1 9/2/2 21/3/3
+f 1/4/4 9/2/2 2/5/5
+f 21/3/3 9/2/2 1/4/4
+f 2/5/5 9/2/2 3/6/6
+f 19/7/7 9/2/2 20/1/1
+f 18/8/8 9/2/2 19/7/7
+f 17/9/9 9/2/2 18/8/8
+f 16/10/10 9/2/2 17/9/9
+f 15/11/11 9/2/2 16/10/10
+f 14/12/12 9/2/2 15/11/11
+f 13/13/13 9/14/2 14/15/12
+f 12/16/14 9/14/2 13/13/13
+f 11/17/15 9/14/2 12/16/14
+f 10/18/16 9/14/2 11/17/15
+f 8/19/17 9/14/2 10/18/16
+f 7/20/18 9/14/2 8/19/17
+f 6/21/19 9/14/2 7/20/18
+f 5/22/20 9/14/2 6/21/19
+f 4/23/21 9/14/2 5/22/20
+f 3/24/6 9/14/2 4/23/21
diff --git a/src/datavis3d/engine/meshes/cubeFlat.obj b/src/datavis3d/engine/meshes/cubeFlat.obj
new file mode 100644
index 00000000..3c8d6d0a
--- /dev/null
+++ b/src/datavis3d/engine/meshes/cubeFlat.obj
@@ -0,0 +1,47 @@
+# Blender v2.66 (sub 0) OBJ File: 'cube.blend'
+# www.blender.org
+o Cube
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v 1.000000 1.000000 -1.000000
+v 1.000000 1.000000 1.000000
+vt 0.998999 0.334334
+vt 0.667668 0.334334
+vt 0.998999 0.665666
+vt 0.332332 0.001001
+vt 0.001001 0.001001
+vt 0.332332 0.332332
+vt 0.332332 0.334334
+vt 0.001001 0.334334
+vt 0.001001 0.665666
+vt 0.665666 0.001001
+vt 0.334334 0.001001
+vt 0.334334 0.332332
+vt 0.665666 0.334334
+vt 0.334334 0.334334
+vt 0.334334 0.665666
+vt 0.667668 0.665666
+vt 0.001001 0.332332
+vt 0.332332 0.665666
+vt 0.665666 0.332332
+vt 0.665666 0.665666
+vn -1.000000 0.000000 0.000000
+vn 0.000000 0.000000 -1.000000
+vn 1.000000 -0.000000 0.000000
+vn 0.000000 0.000000 1.000000
+vn 0.000000 1.000000 0.000000
+s off
+f 5/1/1 6/2/1 1/3/1
+f 6/4/2 7/5/2 2/6/2
+f 7/7/3 8/8/3 4/9/3
+f 8/10/4 5/11/4 1/12/4
+f 8/13/5 7/14/5 6/15/5
+f 6/2/1 2/16/1 1/3/1
+f 7/5/2 3/17/2 2/6/2
+f 3/18/3 7/7/3 4/9/3
+f 4/19/4 8/10/4 1/12/4
+f 5/20/5 8/13/5 6/15/5
diff --git a/src/datavis3d/engine/meshes/cubeSmooth.obj b/src/datavis3d/engine/meshes/cubeSmooth.obj
new file mode 100644
index 00000000..9d147bfd
--- /dev/null
+++ b/src/datavis3d/engine/meshes/cubeSmooth.obj
@@ -0,0 +1,50 @@
+# Blender v2.66 (sub 0) OBJ File: 'cube.blend'
+# www.blender.org
+o Cube
+v -1.000000 -1.000000 1.000000
+v -1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 -1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v 1.000000 1.000000 -1.000000
+v 1.000000 1.000000 1.000000
+vt 0.998999 0.334334
+vt 0.667668 0.334334
+vt 0.998999 0.665666
+vt 0.332332 0.001001
+vt 0.001001 0.001001
+vt 0.332332 0.332332
+vt 0.332332 0.334334
+vt 0.001001 0.334334
+vt 0.001001 0.665666
+vt 0.665666 0.001001
+vt 0.334334 0.001001
+vt 0.334334 0.332332
+vt 0.665666 0.334334
+vt 0.334334 0.334334
+vt 0.334334 0.665666
+vt 0.667668 0.665666
+vt 0.001001 0.332332
+vt 0.332332 0.665666
+vt 0.665666 0.332332
+vt 0.665666 0.665666
+vn -0.577349 0.577349 0.577349
+vn -0.577349 0.577349 -0.577349
+vn -0.707083 0.000000 0.707083
+vn 0.577349 0.577349 -0.577349
+vn -0.707083 0.000000 -0.707083
+vn 0.577349 0.577349 0.577349
+vn 0.707083 0.000000 0.707083
+vn 0.707083 0.000000 -0.707083
+s 1
+f 5/1/1 6/2/2 1/3/3
+f 6/4/2 7/5/4 2/6/5
+f 7/7/4 8/8/6 4/9/7
+f 8/10/6 5/11/1 1/12/3
+f 8/13/6 7/14/4 6/15/2
+f 6/2/2 2/16/5 1/3/3
+f 7/5/4 3/17/8 2/6/5
+f 3/18/8 7/7/4 4/9/7
+f 4/19/7 8/10/6 1/12/3
+f 5/20/1 8/13/6 6/15/2
diff --git a/src/datavis3d/engine/meshes/cylinderFlat.obj b/src/datavis3d/engine/meshes/cylinderFlat.obj
new file mode 100644
index 00000000..2b7e3e5e
--- /dev/null
+++ b/src/datavis3d/engine/meshes/cylinderFlat.obj
@@ -0,0 +1,299 @@
+# Blender v2.66 (sub 0) OBJ File: 'cylinder.blend'
+# www.blender.org
+o Cylinder
+v 0.000000 -1.000000 -1.000000
+v 0.000000 1.000000 -1.000000
+v 0.195090 -1.000000 -0.980785
+v 0.195090 1.000000 -0.980785
+v 0.382683 -1.000000 -0.923880
+v 0.382683 1.000000 -0.923880
+v 0.555570 -1.000000 -0.831470
+v 0.555570 1.000000 -0.831470
+v 0.707107 -1.000000 -0.707107
+v 0.707107 1.000000 -0.707107
+v 0.831470 -1.000000 -0.555570
+v 0.831470 1.000000 -0.555570
+v 0.923880 -1.000000 -0.382683
+v 0.923880 1.000000 -0.382683
+v 0.980785 -1.000000 -0.195090
+v 0.980785 1.000000 -0.195090
+v 1.000000 -1.000000 -0.000000
+v 1.000000 1.000000 -0.000000
+v 0.980785 -1.000000 0.195090
+v 0.980785 1.000000 0.195090
+v 0.923880 -1.000000 0.382683
+v 0.923880 1.000000 0.382683
+v 0.831470 -1.000000 0.555570
+v 0.831470 1.000000 0.555570
+v 0.707107 -1.000000 0.707107
+v 0.707107 1.000000 0.707107
+v 0.555570 -1.000000 0.831470
+v 0.555570 1.000000 0.831470
+v 0.382683 -1.000000 0.923880
+v 0.382683 1.000000 0.923880
+v 0.195090 -1.000000 0.980785
+v 0.195090 1.000000 0.980785
+v -0.000000 -1.000000 1.000000
+v -0.000000 1.000000 1.000000
+v -0.195091 -1.000000 0.980785
+v -0.195091 1.000000 0.980785
+v -0.382684 -1.000000 0.923879
+v -0.382684 1.000000 0.923879
+v -0.555571 -1.000000 0.831469
+v -0.555571 1.000000 0.831469
+v -0.707107 -1.000000 0.707106
+v -0.707107 1.000000 0.707106
+v -0.831470 -1.000000 0.555570
+v -0.831470 1.000000 0.555570
+v -0.923880 -1.000000 0.382683
+v -0.923880 1.000000 0.382683
+v -0.980785 -1.000000 0.195089
+v -0.980785 1.000000 0.195089
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000001
+v -0.980785 -1.000000 -0.195091
+v -0.980785 1.000000 -0.195091
+v -0.923879 -1.000000 -0.382684
+v -0.923879 1.000000 -0.382684
+v -0.831469 -1.000000 -0.555571
+v -0.831469 1.000000 -0.555571
+v -0.707106 -1.000000 -0.707108
+v -0.707106 1.000000 -0.707108
+v -0.555569 -1.000000 -0.831470
+v -0.555569 1.000000 -0.831470
+v -0.382682 -1.000000 -0.923880
+v -0.382682 1.000000 -0.923880
+v -0.195089 -1.000000 -0.980786
+v -0.195089 1.000000 -0.980786
+vt 0.289718 0.879351
+vt 0.288367 0.438844
+vt 0.330714 0.438714
+vt 0.332066 0.879221
+vt 0.370605 0.438592
+vt 0.371956 0.879099
+vt 0.406505 0.438482
+vt 0.407857 0.878988
+vt 0.437036 0.438388
+vt 0.778904 0.000000
+vt 0.780256 0.440507
+vt 0.749725 0.440601
+vt 0.748373 0.000094
+vt 0.713824 0.440711
+vt 0.712473 0.000204
+vt 0.673934 0.440833
+vt 0.672582 0.000326
+vt 0.631586 0.440963
+vt 0.630235 0.000456
+vt 0.588409 0.441095
+vt 0.587057 0.000588
+vt 0.546061 0.441225
+vt 0.544710 0.000718
+vt 0.506171 0.441348
+vt 0.504819 0.000841
+vt 0.470270 0.441458
+vt 0.468919 0.000951
+vt 0.439739 0.441552
+vt 0.720545 0.882916
+vt 0.719194 0.442409
+vt 0.755094 0.442299
+vt 0.756446 0.882806
+vt 0.794985 0.442176
+vt 0.796336 0.882683
+vt 0.837333 0.442046
+vt 0.838684 0.882553
+vt 0.881861 0.882421
+vt 0.880510 0.441914
+vt 0.924209 0.882291
+vt 0.922857 0.441784
+vt 0.964099 0.882168
+vt 0.962748 0.441662
+vt 1.000000 0.882058
+vt 0.717842 0.441552
+vt 0.719194 0.882058
+vt 0.681942 0.441662
+vt 0.683293 0.882169
+vt 0.642051 0.441784
+vt 0.643403 0.882291
+vt 0.599704 0.441914
+vt 0.601055 0.882421
+vt 0.556526 0.442046
+vt 0.557878 0.882553
+vt 0.514179 0.442176
+vt 0.515530 0.882683
+vt 0.474288 0.442299
+vt 0.475640 0.882806
+vt 0.438388 0.442409
+vt 0.097872 0.879939
+vt 0.096520 0.439433
+vt 0.128403 0.879846
+vt 0.127051 0.439339
+vt 0.164303 0.879735
+vt 0.162952 0.439229
+vt 0.204194 0.879613
+vt 0.000000 0.197605
+vt 0.008423 0.155257
+vt 0.000000 0.240783
+vt 0.246541 0.879483
+vt 0.245190 0.438976
+vt 0.202842 0.439106
+vt 0.438388 0.878895
+vt 0.438388 0.001045
+vt 0.998649 0.441552
+vt 0.439739 0.882916
+vt 0.024947 0.115367
+vt 0.048935 0.079466
+vt 0.079466 0.048935
+vt 0.115366 0.024947
+vt 0.155257 0.008424
+vt 0.197605 0.000000
+vt 0.240782 0.000000
+vt 0.283130 0.008423
+vt 0.323021 0.024947
+vt 0.358922 0.048935
+vt 0.389453 0.079466
+vt 0.413441 0.115367
+vt 0.429964 0.155257
+vt 0.438388 0.197605
+vt 0.438388 0.240783
+vt 0.429964 0.283130
+vt 0.413441 0.323021
+vt 0.389453 0.358922
+vt 0.358922 0.389453
+vt 0.323021 0.413441
+vt 0.283130 0.429964
+vt 0.240783 0.438388
+vt 0.197605 0.438388
+vt 0.155257 0.429964
+vt 0.115367 0.413441
+vt 0.079466 0.389453
+vt 0.048935 0.358922
+vt 0.024947 0.323021
+vt 0.008423 0.283130
+vn 0.098017 0.000000 -0.995185
+vn 0.290285 0.000000 -0.956940
+vn 0.471397 0.000000 -0.881921
+vn 0.634393 0.000000 -0.773010
+vn 0.773010 0.000000 -0.634393
+vn 0.881921 0.000000 -0.471397
+vn 0.956940 0.000000 -0.290285
+vn 0.995185 0.000000 -0.098017
+vn 0.995185 0.000000 0.098017
+vn 0.956940 0.000000 0.290285
+vn 0.881921 0.000000 0.471396
+vn 0.773010 0.000000 0.634393
+vn 0.634393 0.000000 0.773010
+vn 0.471397 0.000000 0.881921
+vn 0.290284 0.000000 0.956940
+vn 0.098017 0.000000 0.995185
+vn -0.098018 0.000000 0.995185
+vn -0.290285 0.000000 0.956940
+vn -0.471397 0.000000 0.881921
+vn -0.634394 0.000000 0.773010
+vn -0.773011 0.000000 0.634393
+vn -0.881922 0.000000 0.471396
+vn -0.956941 0.000000 0.290284
+vn -0.995185 0.000000 0.098016
+vn -0.995185 -0.000000 -0.098018
+vn -0.956940 -0.000000 -0.290286
+vn -0.881921 -0.000000 -0.471398
+vn -0.773010 -0.000000 -0.634394
+vn -0.634392 -0.000000 -0.773011
+vn -0.471395 -0.000000 -0.881922
+vn -0.000000 1.000000 0.000000
+vn -0.098017 -0.000000 -0.995185
+vn -0.290283 -0.000000 -0.956941
+s off
+f 1/1/1 2/2/1 4/3/1
+f 3/4/2 4/3/2 6/5/2
+f 5/6/3 6/5/3 8/7/3
+f 7/8/4 8/7/4 10/9/4
+f 9/10/5 10/11/5 12/12/5
+f 11/13/6 12/12/6 14/14/6
+f 13/15/7 14/14/7 16/16/7
+f 15/17/8 16/16/8 18/18/8
+f 17/19/9 18/18/9 20/20/9
+f 19/21/10 20/20/10 22/22/10
+f 21/23/11 22/22/11 24/24/11
+f 23/25/12 24/24/12 26/26/12
+f 25/27/13 26/26/13 28/28/13
+f 27/29/14 28/30/14 30/31/14
+f 29/32/15 30/31/15 32/33/15
+f 31/34/16 32/33/16 34/35/16
+f 33/36/17 34/35/17 35/37/17
+f 35/37/18 36/38/18 37/39/18
+f 37/39/19 38/40/19 39/41/19
+f 39/41/20 40/42/20 41/43/20
+f 41/44/21 42/45/21 43/46/21
+f 43/46/22 44/47/22 45/48/22
+f 45/48/23 46/49/23 47/50/23
+f 47/50/24 48/51/24 49/52/24
+f 49/52/25 50/53/25 51/54/25
+f 51/54/26 52/55/26 53/56/26
+f 53/56/27 54/57/27 55/58/27
+f 55/59/28 56/60/28 57/61/28
+f 57/61/29 58/62/29 59/63/29
+f 59/63/30 60/64/30 61/65/30
+f 4/66/31 2/67/31 6/68/31
+f 63/69/32 64/70/32 1/1/32
+f 61/65/33 62/71/33 63/69/33
+f 3/4/1 1/1/1 4/3/1
+f 5/6/2 3/4/2 6/5/2
+f 7/8/3 5/6/3 8/7/3
+f 9/72/4 7/8/4 10/9/4
+f 11/13/5 9/10/5 12/12/5
+f 13/15/6 11/13/6 14/14/6
+f 15/17/7 13/15/7 16/16/7
+f 17/19/8 15/17/8 18/18/8
+f 19/21/9 17/19/9 20/20/9
+f 21/23/10 19/21/10 22/22/10
+f 23/25/11 21/23/11 24/24/11
+f 25/27/12 23/25/12 26/26/12
+f 27/73/13 25/27/13 28/28/13
+f 29/32/14 27/29/14 30/31/14
+f 31/34/15 29/32/15 32/33/15
+f 33/36/16 31/34/16 34/35/16
+f 34/35/17 36/38/17 35/37/17
+f 36/38/18 38/40/18 37/39/18
+f 38/40/19 40/42/19 39/41/19
+f 40/42/20 42/74/20 41/43/20
+f 42/45/21 44/47/21 43/46/21
+f 44/47/22 46/49/22 45/48/22
+f 46/49/23 48/51/23 47/50/23
+f 48/51/24 50/53/24 49/52/24
+f 50/53/25 52/55/25 51/54/25
+f 52/55/26 54/57/26 53/56/26
+f 54/57/27 56/75/27 55/58/27
+f 56/60/28 58/62/28 57/61/28
+f 58/62/29 60/64/29 59/63/29
+f 60/64/30 62/71/30 61/65/30
+f 2/67/31 64/76/31 6/68/31
+f 64/76/31 62/77/31 6/68/31
+f 62/77/31 60/78/31 6/68/31
+f 60/78/31 58/79/31 6/68/31
+f 58/79/31 56/80/31 6/68/31
+f 56/80/31 54/81/31 6/68/31
+f 54/81/31 52/82/31 6/68/31
+f 52/82/31 50/83/31 6/68/31
+f 50/83/31 48/84/31 6/68/31
+f 48/84/31 46/85/31 6/68/31
+f 46/85/31 44/86/31 6/68/31
+f 44/86/31 42/87/31 6/68/31
+f 42/87/31 40/88/31 6/68/31
+f 40/88/31 38/89/31 6/68/31
+f 38/89/31 36/90/31 6/68/31
+f 36/90/31 34/91/31 6/68/31
+f 34/91/31 32/92/31 6/68/31
+f 32/92/31 30/93/31 6/68/31
+f 30/93/31 28/94/31 6/68/31
+f 28/94/31 26/95/31 6/68/31
+f 26/95/31 24/96/31 6/68/31
+f 24/96/31 22/97/31 6/68/31
+f 22/97/31 20/98/31 6/68/31
+f 20/98/31 18/99/31 6/68/31
+f 18/99/31 16/100/31 6/68/31
+f 16/100/31 14/101/31 6/68/31
+f 14/101/31 12/102/31 6/68/31
+f 12/102/31 10/103/31 8/104/31
+f 6/68/31 12/102/31 8/104/31
+f 64/70/32 2/2/32 1/1/32
+f 62/71/33 64/70/33 63/69/33
diff --git a/src/datavis3d/engine/meshes/cylinderSmooth.obj b/src/datavis3d/engine/meshes/cylinderSmooth.obj
new file mode 100644
index 00000000..6ccbb286
--- /dev/null
+++ b/src/datavis3d/engine/meshes/cylinderSmooth.obj
@@ -0,0 +1,330 @@
+# Blender v2.66 (sub 0) OBJ File: 'cylinder.blend'
+# www.blender.org
+o Cylinder
+v 0.000000 -1.000000 -1.000000
+v 0.000000 1.000000 -1.000000
+v 0.195090 -1.000000 -0.980785
+v 0.195090 1.000000 -0.980785
+v 0.382683 -1.000000 -0.923880
+v 0.382683 1.000000 -0.923880
+v 0.555570 -1.000000 -0.831470
+v 0.555570 1.000000 -0.831470
+v 0.707107 -1.000000 -0.707107
+v 0.707107 1.000000 -0.707107
+v 0.831470 -1.000000 -0.555570
+v 0.831470 1.000000 -0.555570
+v 0.923880 -1.000000 -0.382683
+v 0.923880 1.000000 -0.382683
+v 0.980785 -1.000000 -0.195090
+v 0.980785 1.000000 -0.195090
+v 1.000000 -1.000000 -0.000000
+v 1.000000 1.000000 -0.000000
+v 0.980785 -1.000000 0.195090
+v 0.980785 1.000000 0.195090
+v 0.923880 -1.000000 0.382683
+v 0.923880 1.000000 0.382683
+v 0.831470 -1.000000 0.555570
+v 0.831470 1.000000 0.555570
+v 0.707107 -1.000000 0.707107
+v 0.707107 1.000000 0.707107
+v 0.555570 -1.000000 0.831470
+v 0.555570 1.000000 0.831470
+v 0.382683 -1.000000 0.923880
+v 0.382683 1.000000 0.923880
+v 0.195090 -1.000000 0.980785
+v 0.195090 1.000000 0.980785
+v -0.000000 -1.000000 1.000000
+v -0.000000 1.000000 1.000000
+v -0.195091 -1.000000 0.980785
+v -0.195091 1.000000 0.980785
+v -0.382684 -1.000000 0.923879
+v -0.382684 1.000000 0.923879
+v -0.555571 -1.000000 0.831469
+v -0.555571 1.000000 0.831469
+v -0.707107 -1.000000 0.707106
+v -0.707107 1.000000 0.707106
+v -0.831470 -1.000000 0.555570
+v -0.831470 1.000000 0.555570
+v -0.923880 -1.000000 0.382683
+v -0.923880 1.000000 0.382683
+v -0.980785 -1.000000 0.195089
+v -0.980785 1.000000 0.195089
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000001
+v -0.980785 -1.000000 -0.195091
+v -0.980785 1.000000 -0.195091
+v -0.923879 -1.000000 -0.382684
+v -0.923879 1.000000 -0.382684
+v -0.831469 -1.000000 -0.555571
+v -0.831469 1.000000 -0.555571
+v -0.707106 -1.000000 -0.707108
+v -0.707106 1.000000 -0.707108
+v -0.555569 -1.000000 -0.831470
+v -0.555569 1.000000 -0.831470
+v -0.382682 -1.000000 -0.923880
+v -0.382682 1.000000 -0.923880
+v -0.195089 -1.000000 -0.980786
+v -0.195089 1.000000 -0.980786
+vt 0.289718 0.879351
+vt 0.288367 0.438844
+vt 0.330714 0.438714
+vt 0.332066 0.879221
+vt 0.370605 0.438592
+vt 0.371956 0.879099
+vt 0.406505 0.438482
+vt 0.407857 0.878988
+vt 0.437036 0.438388
+vt 0.778904 0.000000
+vt 0.780256 0.440507
+vt 0.749725 0.440601
+vt 0.748373 0.000094
+vt 0.713824 0.440711
+vt 0.712473 0.000204
+vt 0.673934 0.440833
+vt 0.672582 0.000326
+vt 0.631586 0.440963
+vt 0.630235 0.000456
+vt 0.588409 0.441095
+vt 0.587057 0.000588
+vt 0.546061 0.441225
+vt 0.544710 0.000718
+vt 0.506171 0.441348
+vt 0.504819 0.000841
+vt 0.470270 0.441458
+vt 0.468919 0.000951
+vt 0.439739 0.441552
+vt 0.720545 0.882916
+vt 0.719194 0.442409
+vt 0.755094 0.442299
+vt 0.756446 0.882806
+vt 0.794985 0.442176
+vt 0.796336 0.882683
+vt 0.837333 0.442046
+vt 0.838684 0.882553
+vt 0.881861 0.882421
+vt 0.880510 0.441914
+vt 0.924209 0.882291
+vt 0.922857 0.441784
+vt 0.964099 0.882168
+vt 0.962748 0.441662
+vt 1.000000 0.882058
+vt 0.717842 0.441552
+vt 0.719194 0.882058
+vt 0.681942 0.441662
+vt 0.683293 0.882169
+vt 0.642051 0.441784
+vt 0.643403 0.882291
+vt 0.599704 0.441914
+vt 0.601055 0.882421
+vt 0.556526 0.442046
+vt 0.557878 0.882553
+vt 0.514179 0.442176
+vt 0.515530 0.882683
+vt 0.474288 0.442299
+vt 0.475640 0.882806
+vt 0.438388 0.442409
+vt 0.097872 0.879939
+vt 0.096520 0.439433
+vt 0.128403 0.879846
+vt 0.127051 0.439339
+vt 0.164303 0.879735
+vt 0.162952 0.439229
+vt 0.204194 0.879613
+vt 0.000000 0.197605
+vt 0.008423 0.155257
+vt 0.000000 0.240783
+vt 0.246541 0.879483
+vt 0.245190 0.438976
+vt 0.202842 0.439106
+vt 0.438388 0.878895
+vt 0.438388 0.001045
+vt 0.998649 0.441552
+vt 0.439739 0.882916
+vt 0.024947 0.115367
+vt 0.048935 0.079466
+vt 0.079466 0.048935
+vt 0.115366 0.024947
+vt 0.155257 0.008424
+vt 0.197605 0.000000
+vt 0.240782 0.000000
+vt 0.283130 0.008423
+vt 0.323021 0.024947
+vt 0.358922 0.048935
+vt 0.389453 0.079466
+vt 0.413441 0.115367
+vt 0.429964 0.155257
+vt 0.438388 0.197605
+vt 0.438388 0.240783
+vt 0.429964 0.283130
+vt 0.413441 0.323021
+vt 0.389453 0.358922
+vt 0.358922 0.389453
+vt 0.323021 0.413441
+vt 0.283130 0.429964
+vt 0.240783 0.438388
+vt 0.197605 0.438388
+vt 0.155257 0.429964
+vt 0.115367 0.413441
+vt 0.079466 0.389453
+vt 0.048935 0.358922
+vt 0.024947 0.323021
+vt 0.008423 0.283130
+vn 0.000000 0.000000 -1.000000
+vn 0.000000 0.685690 -0.727866
+vn 0.142003 0.685690 -0.713889
+vn 0.195074 0.000000 -0.980773
+vn 0.278542 0.685690 -0.672475
+vn 0.382672 0.000000 -0.923856
+vn 0.404370 0.685690 -0.605213
+vn 0.555559 0.000000 -0.831446
+vn 0.514664 0.685690 -0.514664
+vn 0.707083 0.000000 -0.707083
+vn 0.605213 0.685690 -0.404370
+vn 0.831446 0.000000 -0.555559
+vn 0.672475 0.685690 -0.278542
+vn 0.923856 0.000000 -0.382672
+vn 0.713889 0.685690 -0.142003
+vn 0.980773 0.000000 -0.195074
+vn 0.727866 0.685690 0.000000
+vn 1.000000 0.000000 0.000000
+vn 0.713889 0.685690 0.142003
+vn 0.980773 0.000000 0.195074
+vn 0.672475 0.685690 0.278542
+vn 0.923856 0.000000 0.382672
+vn 0.605213 0.685690 0.404370
+vn 0.831446 0.000000 0.555559
+vn 0.514664 0.685690 0.514664
+vn 0.707083 0.000000 0.707083
+vn 0.404370 0.685690 0.605213
+vn 0.555559 0.000000 0.831446
+vn 0.278542 0.685690 0.672475
+vn 0.382672 0.000000 0.923856
+vn 0.142003 0.685690 0.713889
+vn 0.195074 0.000000 0.980773
+vn 0.000000 0.685690 0.727866
+vn 0.000000 0.000000 0.999969
+vn -0.195074 0.000000 0.980773
+vn -0.142003 0.685690 0.713889
+vn -0.382672 0.000000 0.923856
+vn -0.278542 0.685690 0.672475
+vn -0.555559 0.000000 0.831446
+vn -0.404370 0.685690 0.605213
+vn -0.707083 0.000000 0.707083
+vn -0.514664 0.685690 0.514664
+vn -0.831446 0.000000 0.555559
+vn -0.605213 0.685690 0.404370
+vn -0.923856 0.000000 0.382672
+vn -0.672475 0.685690 0.278542
+vn -0.980773 0.000000 0.195074
+vn -0.713889 0.685690 0.142003
+vn -1.000000 0.000000 0.000000
+vn -0.727866 0.685690 0.000000
+vn -0.980773 0.000000 -0.195074
+vn -0.713889 0.685690 -0.142003
+vn -0.923856 0.000000 -0.382672
+vn -0.672475 0.685690 -0.278542
+vn -0.831446 0.000000 -0.555559
+vn -0.605213 0.685690 -0.404370
+vn -0.707083 0.000000 -0.707083
+vn -0.514664 0.685690 -0.514695
+vn -0.555559 0.000000 -0.831446
+vn -0.404370 0.685690 -0.605213
+vn -0.382672 0.000000 -0.923856
+vn -0.195074 0.000000 -0.980773
+vn -0.142003 0.685690 -0.713889
+vn -0.278542 0.685690 -0.672475
+s 1
+f 1/1/1 2/2/2 4/3/3
+f 3/4/4 4/3/3 6/5/5
+f 5/6/6 6/5/5 8/7/7
+f 7/8/8 8/7/7 10/9/9
+f 9/10/10 10/11/9 12/12/11
+f 11/13/12 12/12/11 14/14/13
+f 13/15/14 14/14/13 16/16/15
+f 15/17/16 16/16/15 18/18/17
+f 17/19/18 18/18/17 20/20/19
+f 19/21/20 20/20/19 22/22/21
+f 21/23/22 22/22/21 24/24/23
+f 23/25/24 24/24/23 26/26/25
+f 25/27/26 26/26/25 28/28/27
+f 27/29/28 28/30/27 30/31/29
+f 29/32/30 30/31/29 32/33/31
+f 31/34/32 32/33/31 34/35/33
+f 33/36/34 34/35/33 35/37/35
+f 35/37/35 36/38/36 37/39/37
+f 37/39/37 38/40/38 39/41/39
+f 39/41/39 40/42/40 41/43/41
+f 41/44/41 42/45/42 43/46/43
+f 43/46/43 44/47/44 45/48/45
+f 45/48/45 46/49/46 47/50/47
+f 47/50/47 48/51/48 49/52/49
+f 49/52/49 50/53/50 51/54/51
+f 51/54/51 52/55/52 53/56/53
+f 53/56/53 54/57/54 55/58/55
+f 55/59/55 56/60/56 57/61/57
+f 57/61/57 58/62/58 59/63/59
+f 59/63/59 60/64/60 61/65/61
+f 4/66/3 2/67/2 6/68/5
+f 63/69/62 64/70/63 1/1/1
+f 61/65/61 62/71/64 63/69/62
+f 3/4/4 1/1/1 4/3/3
+f 5/6/6 3/4/4 6/5/5
+f 7/8/8 5/6/6 8/7/7
+f 9/72/10 7/8/8 10/9/9
+f 11/13/12 9/10/10 12/12/11
+f 13/15/14 11/13/12 14/14/13
+f 15/17/16 13/15/14 16/16/15
+f 17/19/18 15/17/16 18/18/17
+f 19/21/20 17/19/18 20/20/19
+f 21/23/22 19/21/20 22/22/21
+f 23/25/24 21/23/22 24/24/23
+f 25/27/26 23/25/24 26/26/25
+f 27/73/28 25/27/26 28/28/27
+f 29/32/30 27/29/28 30/31/29
+f 31/34/32 29/32/30 32/33/31
+f 33/36/34 31/34/32 34/35/33
+f 34/35/33 36/38/36 35/37/35
+f 36/38/36 38/40/38 37/39/37
+f 38/40/38 40/42/40 39/41/39
+f 40/42/40 42/74/42 41/43/41
+f 42/45/42 44/47/44 43/46/43
+f 44/47/44 46/49/46 45/48/45
+f 46/49/46 48/51/48 47/50/47
+f 48/51/48 50/53/50 49/52/49
+f 50/53/50 52/55/52 51/54/51
+f 52/55/52 54/57/54 53/56/53
+f 54/57/54 56/75/56 55/58/55
+f 56/60/56 58/62/58 57/61/57
+f 58/62/58 60/64/60 59/63/59
+f 60/64/60 62/71/64 61/65/61
+f 2/67/2 64/76/63 6/68/5
+f 64/76/63 62/77/64 6/68/5
+f 62/77/64 60/78/60 6/68/5
+f 60/78/60 58/79/58 6/68/5
+f 58/79/58 56/80/56 6/68/5
+f 56/80/56 54/81/54 6/68/5
+f 54/81/54 52/82/52 6/68/5
+f 52/82/52 50/83/50 6/68/5
+f 50/83/50 48/84/48 6/68/5
+f 48/84/48 46/85/46 6/68/5
+f 46/85/46 44/86/44 6/68/5
+f 44/86/44 42/87/42 6/68/5
+f 42/87/42 40/88/40 6/68/5
+f 40/88/40 38/89/38 6/68/5
+f 38/89/38 36/90/36 6/68/5
+f 36/90/36 34/91/33 6/68/5
+f 34/91/33 32/92/31 6/68/5
+f 32/92/31 30/93/29 6/68/5
+f 30/93/29 28/94/27 6/68/5
+f 28/94/27 26/95/25 6/68/5
+f 26/95/25 24/96/23 6/68/5
+f 24/96/23 22/97/21 6/68/5
+f 22/97/21 20/98/19 6/68/5
+f 20/98/19 18/99/17 6/68/5
+f 18/99/17 16/100/15 6/68/5
+f 16/100/15 14/101/13 6/68/5
+f 14/101/13 12/102/11 6/68/5
+f 12/102/11 10/103/9 8/104/7
+f 6/68/5 12/102/11 8/104/7
+f 64/70/63 2/2/2 1/1/1
+f 62/71/64 64/70/63 63/69/62
diff --git a/src/datavis3d/engine/meshes/plane.obj b/src/datavis3d/engine/meshes/plane.obj
new file mode 100644
index 00000000..96ac0dd7
--- /dev/null
+++ b/src/datavis3d/engine/meshes/plane.obj
@@ -0,0 +1,15 @@
+# Blender v2.66 (sub 0) OBJ File: 'plane.blend'
+# www.blender.org
+o Plane
+v -1.000000 -1.000000 -0.000001
+v -1.000000 1.000000 -0.000000
+v 1.000000 -1.000000 0.000000
+v 1.000000 1.000000 0.000001
+vt 0.003058 1.000000
+vt 0.000000 0.003058
+vt 1.000000 0.996942
+vt 0.996942 0.000000
+vn -0.000001 -0.000001 1.000000
+s off
+f 2/1/1 1/2/1 4/3/1
+f 1/2/1 3/4/1 4/3/1
diff --git a/src/datavis3d/engine/meshes/pyramidFlat.obj b/src/datavis3d/engine/meshes/pyramidFlat.obj
new file mode 100644
index 00000000..35edb477
--- /dev/null
+++ b/src/datavis3d/engine/meshes/pyramidFlat.obj
@@ -0,0 +1,22 @@
+# Blender v2.66 (sub 0) OBJ File: 'pyramid.blend'
+# www.blender.org
+o Cone_Cone.001
+v 1.000000 -1.000000 -0.999999
+v 0.999999 -1.000000 1.000000
+v -1.000000 -1.000000 0.999999
+v 0.000000 1.000000 0.000000
+v -0.999999 -1.000000 -1.000000
+vt 0.999900 0.000100
+vt 0.500000 0.500000
+vt 0.000100 0.000100
+vt 0.000100 0.999900
+vt 0.999900 0.999900
+vn -0.894427 0.447214 -0.000000
+vn 0.894427 0.447213 0.000000
+vn 0.000000 0.447214 -0.894427
+vn -0.000000 0.447214 0.894427
+s off
+f 3/1/1 4/2/1 5/3/1
+f 1/4/2 4/2/2 2/5/2
+f 5/3/3 4/2/3 1/4/3
+f 2/5/4 4/2/4 3/1/4
diff --git a/src/datavis3d/engine/meshes/pyramidSmooth.obj b/src/datavis3d/engine/meshes/pyramidSmooth.obj
new file mode 100644
index 00000000..b11c8750
--- /dev/null
+++ b/src/datavis3d/engine/meshes/pyramidSmooth.obj
@@ -0,0 +1,23 @@
+# Blender v2.66 (sub 0) OBJ File: 'pyramid.blend'
+# www.blender.org
+o Cone_Cone.001
+v 1.000000 -1.000000 -0.999999
+v 0.999999 -1.000000 1.000000
+v -1.000000 -1.000000 0.999999
+v 0.000000 1.000000 0.000000
+v -0.999999 -1.000000 -1.000000
+vt 0.999900 0.000100
+vt 0.500000 0.500000
+vt 0.000100 0.000100
+vt 0.000100 0.999900
+vt 0.999900 0.999900
+vn -0.577349 0.577349 0.577349
+vn 0.000000 1.000000 0.000000
+vn -0.577349 0.577349 -0.577349
+vn 0.577349 0.577349 -0.577349
+vn 0.577349 0.577349 0.577349
+s 1
+f 3/1/1 4/2/2 5/3/3
+f 1/4/4 4/2/2 2/5/5
+f 5/3/3 4/2/2 1/4/4
+f 2/5/5 4/2/2 3/1/1
diff --git a/src/datavis3d/engine/meshes/sphere.obj b/src/datavis3d/engine/meshes/sphere.obj
new file mode 100644
index 00000000..671a7bcc
--- /dev/null
+++ b/src/datavis3d/engine/meshes/sphere.obj
@@ -0,0 +1,1301 @@
+# Blender v2.66 (sub 0) OBJ File: 'sphere.blend'
+# www.blender.org
+o Sphere
+v -0.195090 0.980785 0.000000
+v -0.382683 0.923880 0.000000
+v -0.555570 0.831470 0.000000
+v -0.707107 0.707107 0.000000
+v -0.831470 0.555570 0.000000
+v -0.923880 0.382683 0.000000
+v -0.980785 0.195090 0.000000
+v -1.000000 0.000000 0.000000
+v -0.980785 -0.195090 0.000000
+v -0.923880 -0.382683 0.000000
+v -0.831470 -0.555570 0.000000
+v -0.707107 -0.707107 0.000000
+v -0.555570 -0.831470 0.000000
+v -0.382683 -0.923880 0.000000
+v -0.195090 -0.980785 0.000000
+v -0.180240 0.980785 -0.074658
+v -0.353553 0.923880 -0.146447
+v -0.513280 0.831470 -0.212608
+v -0.653281 0.707107 -0.270598
+v -0.768178 0.555570 -0.318190
+v -0.853553 0.382683 -0.353553
+v -0.906127 0.195090 -0.375330
+v -0.923880 0.000000 -0.382684
+v -0.906127 -0.195090 -0.375330
+v -0.853553 -0.382683 -0.353554
+v -0.768178 -0.555570 -0.318190
+v -0.653281 -0.707107 -0.270598
+v -0.513280 -0.831470 -0.212608
+v -0.353553 -0.923880 -0.146447
+v -0.180240 -0.980785 -0.074658
+v 0.000000 -1.000000 0.000000
+v -0.137950 0.980785 -0.137950
+v -0.270598 0.923880 -0.270598
+v -0.392847 0.831470 -0.392848
+v -0.500000 0.707107 -0.500000
+v -0.587938 0.555570 -0.587938
+v -0.653281 0.382683 -0.653282
+v -0.693520 0.195090 -0.693520
+v -0.707107 0.000000 -0.707107
+v -0.693520 -0.195090 -0.693520
+v -0.653281 -0.382683 -0.653282
+v -0.587938 -0.555570 -0.587938
+v -0.500000 -0.707107 -0.500000
+v -0.392847 -0.831470 -0.392848
+v -0.270598 -0.923880 -0.270598
+v -0.137949 -0.980785 -0.137950
+v -0.074658 0.980785 -0.180240
+v -0.146446 0.923880 -0.353554
+v -0.212607 0.831470 -0.513280
+v -0.270598 0.707107 -0.653282
+v -0.318189 0.555570 -0.768178
+v -0.353553 0.382683 -0.853554
+v -0.375330 0.195090 -0.906128
+v -0.382683 0.000000 -0.923880
+v -0.375330 -0.195090 -0.906128
+v -0.353553 -0.382683 -0.853554
+v -0.318189 -0.555570 -0.768178
+v -0.270598 -0.707107 -0.653282
+v -0.212607 -0.831470 -0.513280
+v -0.146446 -0.923880 -0.353554
+v -0.074658 -0.980785 -0.180240
+v 0.000000 0.980785 -0.195091
+v 0.000000 0.923880 -0.382684
+v 0.000000 0.831470 -0.555570
+v 0.000000 0.707107 -0.707107
+v 0.000000 0.555570 -0.831470
+v 0.000000 0.382683 -0.923880
+v 0.000000 0.195090 -0.980785
+v 0.000000 0.000000 -1.000000
+v 0.000000 -0.195090 -0.980785
+v 0.000000 -0.382683 -0.923880
+v 0.000000 -0.555570 -0.831470
+v 0.000000 -0.707107 -0.707107
+v 0.000000 -0.831470 -0.555570
+v 0.000000 -0.923880 -0.382684
+v 0.000000 -0.980785 -0.195090
+v 0.074658 0.980785 -0.180240
+v 0.146447 0.923880 -0.353554
+v 0.212608 0.831470 -0.513280
+v 0.270598 0.707107 -0.653282
+v 0.318190 0.555570 -0.768178
+v 0.353554 0.382683 -0.853553
+v 0.375331 0.195090 -0.906128
+v 0.382684 0.000000 -0.923880
+v 0.375331 -0.195090 -0.906128
+v 0.353554 -0.382683 -0.853553
+v 0.318190 -0.555570 -0.768178
+v 0.270598 -0.707107 -0.653282
+v 0.212608 -0.831470 -0.513280
+v 0.146447 -0.923880 -0.353554
+v 0.074658 -0.980785 -0.180240
+v 0.137950 0.980785 -0.137950
+v 0.270599 0.923880 -0.270598
+v 0.392848 0.831470 -0.392848
+v 0.500000 0.707107 -0.500000
+v 0.587938 0.555570 -0.587938
+v 0.653282 0.382683 -0.653282
+v 0.693520 0.195090 -0.693520
+v 0.707107 0.000000 -0.707107
+v 0.693520 -0.195090 -0.693520
+v 0.653282 -0.382683 -0.653281
+v 0.587938 -0.555570 -0.587938
+v 0.500000 -0.707107 -0.500000
+v 0.392848 -0.831470 -0.392848
+v 0.270599 -0.923880 -0.270598
+v 0.137950 -0.980785 -0.137950
+v 0.180241 0.980785 -0.074658
+v 0.353554 0.923880 -0.146447
+v 0.513280 0.831470 -0.212608
+v 0.653282 0.707107 -0.270598
+v 0.768178 0.555570 -0.318190
+v 0.853554 0.382683 -0.353553
+v 0.906128 0.195090 -0.375330
+v 0.923880 0.000000 -0.382683
+v 0.906128 -0.195090 -0.375330
+v 0.853554 -0.382683 -0.353553
+v 0.768178 -0.555570 -0.318190
+v 0.653282 -0.707107 -0.270598
+v 0.513280 -0.831470 -0.212608
+v 0.353554 -0.923880 -0.146447
+v 0.180240 -0.980785 -0.074658
+v 0.195091 0.980785 0.000000
+v 0.382684 0.923880 0.000000
+v 0.555571 0.831470 0.000000
+v 0.707107 0.707107 0.000000
+v 0.831470 0.555570 0.000000
+v 0.923880 0.382683 0.000000
+v 0.980786 0.195090 0.000000
+v 1.000000 0.000000 0.000000
+v 0.980786 -0.195090 0.000000
+v 0.923880 -0.382683 0.000000
+v 0.831470 -0.555570 0.000000
+v 0.707107 -0.707107 0.000000
+v 0.555571 -0.831470 0.000000
+v 0.382684 -0.923880 0.000000
+v 0.195091 -0.980785 0.000000
+v 0.180241 0.980785 0.074658
+v 0.353554 0.923880 0.146447
+v 0.513280 0.831470 0.212608
+v 0.653282 0.707107 0.270598
+v 0.768178 0.555570 0.318190
+v 0.853554 0.382683 0.353553
+v 0.906128 0.195090 0.375330
+v 0.923880 0.000000 0.382684
+v 0.906128 -0.195090 0.375330
+v 0.853554 -0.382683 0.353553
+v 0.768178 -0.555570 0.318190
+v 0.653282 -0.707107 0.270598
+v 0.513280 -0.831470 0.212608
+v 0.353554 -0.923880 0.146447
+v 0.180240 -0.980785 0.074658
+v 0.137950 0.980785 0.137950
+v 0.270599 0.923880 0.270598
+v 0.392848 0.831470 0.392848
+v 0.500000 0.707107 0.500000
+v 0.587938 0.555570 0.587938
+v 0.653282 0.382683 0.653282
+v 0.693520 0.195090 0.693520
+v 0.707107 0.000000 0.707107
+v 0.693520 -0.195090 0.693520
+v 0.653282 -0.382683 0.653282
+v 0.587938 -0.555570 0.587938
+v 0.500000 -0.707107 0.500000
+v 0.392848 -0.831470 0.392848
+v 0.270599 -0.923880 0.270598
+v 0.137950 -0.980785 0.137950
+v 0.074658 0.980785 0.180240
+v 0.146447 0.923880 0.353554
+v 0.212608 0.831470 0.513280
+v 0.270598 0.707107 0.653282
+v 0.318190 0.555570 0.768178
+v 0.353554 0.382683 0.853553
+v 0.375331 0.195090 0.906128
+v 0.382684 0.000000 0.923880
+v 0.375331 -0.195090 0.906128
+v 0.353554 -0.382683 0.853553
+v 0.318190 -0.555570 0.768178
+v 0.270598 -0.707107 0.653282
+v 0.212608 -0.831470 0.513280
+v 0.146447 -0.923880 0.353554
+v 0.074658 -0.980785 0.180240
+v 0.000000 0.980785 0.195091
+v 0.000000 0.923880 0.382684
+v 0.000000 0.831470 0.555570
+v 0.000000 0.707107 0.707107
+v 0.000000 0.555570 0.831470
+v 0.000000 0.382683 0.923880
+v 0.000000 0.195090 0.980785
+v 0.000000 0.000000 1.000000
+v 0.000000 -0.195090 0.980785
+v 0.000000 -0.382683 0.923879
+v 0.000000 -0.555570 0.831470
+v 0.000000 -0.707107 0.707107
+v 0.000000 -0.831470 0.555570
+v 0.000000 -0.923880 0.382684
+v 0.000000 -0.980785 0.195090
+v -0.074658 0.980785 0.180240
+v -0.146446 0.923880 0.353554
+v -0.212607 0.831470 0.513280
+v -0.270598 0.707107 0.653282
+v -0.318189 0.555570 0.768178
+v -0.353553 0.382683 0.853553
+v -0.375330 0.195090 0.906128
+v -0.382683 0.000000 0.923880
+v -0.375330 -0.195090 0.906128
+v -0.353553 -0.382683 0.853553
+v -0.318189 -0.555570 0.768178
+v -0.270598 -0.707107 0.653282
+v -0.212607 -0.831470 0.513280
+v -0.146446 -0.923880 0.353554
+v -0.074658 -0.980785 0.180240
+v 0.000000 1.000000 0.000000
+v -0.137950 0.980785 0.137950
+v -0.270598 0.923880 0.270598
+v -0.392847 0.831470 0.392848
+v -0.500000 0.707107 0.500000
+v -0.587938 0.555570 0.587938
+v -0.653281 0.382683 0.653281
+v -0.693520 0.195090 0.693520
+v -0.707107 0.000000 0.707107
+v -0.693520 -0.195090 0.693520
+v -0.653281 -0.382683 0.653281
+v -0.587938 -0.555570 0.587938
+v -0.500000 -0.707107 0.500000
+v -0.392847 -0.831470 0.392848
+v -0.270598 -0.923880 0.270598
+v -0.137949 -0.980785 0.137950
+v -0.180240 0.980785 0.074658
+v -0.353553 0.923880 0.146447
+v -0.513280 0.831470 0.212608
+v -0.653281 0.707107 0.270598
+v -0.768177 0.555570 0.318190
+v -0.853553 0.382683 0.353553
+v -0.906127 0.195090 0.375330
+v -0.923879 0.000000 0.382683
+v -0.906127 -0.195090 0.375330
+v -0.853553 -0.382683 0.353553
+v -0.768177 -0.555570 0.318190
+v -0.653281 -0.707107 0.270598
+v -0.513280 -0.831470 0.212608
+v -0.353553 -0.923880 0.146447
+v -0.180240 -0.980785 0.074658
+vt 0.040867 0.325557
+vt 0.048386 0.386583
+vt 0.001015 0.334499
+vt 0.081872 0.692529
+vt 0.092315 0.752973
+vt 0.006404 0.709363
+vt 1.031336 0.264931
+vt 1.040867 0.325557
+vt 0.999822 0.272029
+vt 0.073887 0.631595
+vt 0.005301 0.646891
+vt 0.333915 0.937286
+vt 0.448527 0.905466
+vt 0.447682 0.976645
+vt 1.017784 0.205113
+vt 0.998129 0.209571
+vt 0.067156 0.570413
+vt 0.004397 0.584414
+vt 0.196016 0.918498
+vt 0.034176 0.958662
+vt 0.060989 0.509119
+vt 0.003585 0.521934
+vt 0.135028 0.869370
+vt 0.015221 0.896641
+vt 0.054891 0.447811
+vt 0.002796 0.459454
+vt 0.107782 0.812401
+vt 0.010297 0.834265
+vt 0.001965 0.396975
+vt 0.007907 0.771825
+vt 0.978319 0.207096
+vt 1.004397 0.584414
+vt 1.005301 0.646891
+vt 0.941200 0.576589
+vt 1.034176 0.958662
+vt 0.823807 0.933258
+vt 1.003585 0.521934
+vt 0.945911 0.514786
+vt 1.015221 0.896641
+vt 0.885287 0.880701
+vt 1.002796 0.459454
+vt 0.950535 0.452971
+vt 1.010297 0.834265
+vt 0.908873 0.821779
+vt 1.001965 0.396975
+vt 0.955439 0.391196
+vt 1.007907 0.771825
+vt 0.921503 0.761167
+vt 1.001015 0.334499
+vt 0.961079 0.329532
+vt 1.006404 0.709363
+vt 0.929787 0.699898
+vt 0.968202 0.268089
+vt 0.936013 0.638321
+vt 0.488610 0.915189
+vt 0.647808 0.950687
+vt 0.921611 0.311033
+vt 0.859136 0.666985
+vt 0.937209 0.253354
+vt 0.870446 0.607941
+vt 0.532175 0.909643
+vt 0.657607 0.903302
+vt 0.959449 0.197860
+vt 0.880347 0.548455
+vt 0.745300 0.879338
+vt 0.889690 0.488794
+vt 0.796385 0.834663
+vt 0.899158 0.429173
+vt 0.825891 0.781668
+vt 0.909472 0.369816
+vt 0.845097 0.725165
+vt 0.848920 0.390841
+vt 0.761226 0.728711
+vt 0.864196 0.334814
+vt 0.780693 0.674598
+vt 0.882867 0.280332
+vt 0.796418 0.618773
+vt 0.907539 0.228698
+vt 0.810089 0.562031
+vt 0.558962 0.891763
+vt 0.641452 0.857179
+vt 0.942759 0.182515
+vt 0.822818 0.504873
+vt 0.697492 0.824480
+vt 0.835477 0.447684
+vt 0.735147 0.779653
+vt 0.879896 0.195479
+vt 0.753309 0.508011
+vt 0.618082 0.815427
+vt 0.767315 0.452094
+vt 0.657173 0.773912
+vt 0.782092 0.396562
+vt 0.685241 0.725518
+vt 0.798714 0.341964
+vt 0.706593 0.673391
+vt 0.818709 0.289116
+vt 0.723996 0.619193
+vt 0.844487 0.239416
+vt 0.739178 0.563865
+vt 0.567268 0.868303
+vt 0.563300 0.844314
+vt 0.770454 0.236269
+vt 0.670392 0.566231
+vt 0.805029 0.190637
+vt 0.683774 0.509644
+vt 0.551952 0.822879
+vt 0.929896 0.162212
+vt 0.855308 0.155368
+vt 0.697011 0.452991
+vt 0.591182 0.780044
+vt 0.710973 0.396675
+vt 0.618699 0.730484
+vt 0.726705 0.341193
+vt 0.639317 0.677374
+vt 0.745717 0.287291
+vt 0.655961 0.622327
+vt 0.665037 0.288362
+vt 0.594131 0.638967
+vt 0.684737 0.232805
+vt 0.605914 0.580518
+vt 0.713639 0.180821
+vt 0.616615 0.521685
+vt 0.760428 0.136665
+vt 0.627046 0.462757
+vt 0.536166 0.805967
+vt 0.923407 0.138703
+vt 0.836350 0.110271
+vt 0.637946 0.403995
+vt 0.562017 0.752770
+vt 0.650183 0.345708
+vt 0.580132 0.696622
+vt 0.517784 0.794886
+vt 0.927547 0.114679
+vt 0.833915 0.062714
+vt 0.573887 0.368405
+vt 0.531336 0.735069
+vt 0.581872 0.307471
+vt 0.540867 0.674443
+vt 0.592315 0.247027
+vt 0.548386 0.613417
+vt 0.607782 0.187599
+vt 0.554891 0.552189
+vt 0.635028 0.130630
+vt 0.560989 0.490881
+vt 0.696016 0.081502
+vt 0.567156 0.429587
+vt 0.502796 0.540546
+vt 0.515221 0.103359
+vt 0.503585 0.478066
+vt 0.534176 0.041338
+vt 0.504397 0.415586
+vt 0.498129 0.790428
+vt 0.948527 0.094534
+vt 0.947682 0.023355
+vt 0.505301 0.353109
+vt 0.499822 0.727971
+vt 0.506404 0.290637
+vt 0.501015 0.665501
+vt 0.507907 0.228175
+vt 0.501965 0.603025
+vt 0.510297 0.165735
+vt 0.429787 0.300102
+vt 0.461079 0.670468
+vt 0.421503 0.238833
+vt 0.455439 0.608804
+vt 0.408873 0.178221
+vt 0.445911 0.485214
+vt 0.385287 0.119299
+vt 1.323807 0.066742
+vt 0.441200 0.423411
+vt 0.478319 0.792904
+vt 0.988610 0.084811
+vt 1.147808 0.049313
+vt 0.436013 0.361679
+vt 0.468202 0.731911
+vt 0.147808 0.049313
+vt 0.323807 0.066742
+vt 0.245300 0.120661
+vt 0.380347 0.451545
+vt 0.459449 0.802140
+vt 0.032175 0.090357
+vt 0.157607 0.096698
+vt 0.370446 0.392059
+vt 0.437209 0.746646
+vt 0.359136 0.333015
+vt 0.421611 0.688967
+vt 0.345097 0.274835
+vt 0.450536 0.547029
+vt 0.409472 0.630184
+vt 0.325892 0.218332
+vt 0.399158 0.570827
+vt 0.296385 0.165337
+vt 0.389690 0.511206
+vt 0.261226 0.271289
+vt 0.348920 0.609159
+vt 0.235147 0.220347
+vt 0.335478 0.552316
+vt 0.197492 0.175520
+vt 0.322818 0.495127
+vt 0.442759 0.817485
+vt 0.058962 0.108237
+vt 0.141452 0.142821
+vt 0.310089 0.437969
+vt 0.407539 0.771302
+vt 0.296418 0.381227
+vt 0.382867 0.719668
+vt 0.280693 0.325402
+vt 0.364196 0.665186
+vt 0.223996 0.380807
+vt 0.318709 0.710884
+vt 0.206593 0.326609
+vt 0.298714 0.658036
+vt 0.185241 0.274482
+vt 0.282092 0.603438
+vt 0.157173 0.226088
+vt 0.267315 0.547906
+vt 0.118082 0.184573
+vt 0.253309 0.491989
+vt 0.379896 0.804521
+vt 0.067268 0.131697
+vt 0.063300 0.155685
+vt 0.239178 0.436135
+vt 0.344487 0.760584
+vt 0.091182 0.219955
+vt 0.197011 0.547009
+vt 0.429896 0.837788
+vt 0.355308 0.844632
+vt 0.051952 0.177121
+vt 0.183774 0.490356
+vt 0.305029 0.809363
+vt 0.170392 0.433769
+vt 0.270454 0.763731
+vt 0.155961 0.377673
+vt 0.245717 0.712709
+vt 0.226706 0.658807
+vt 0.118699 0.269516
+vt 0.210973 0.603325
+vt 0.139317 0.322626
+vt 0.094131 0.361033
+vt 0.165037 0.711638
+vt 0.080132 0.303378
+vt 0.150183 0.654292
+vt 0.062017 0.247229
+vt 0.137946 0.596005
+vt 0.423407 0.861296
+vt 0.336350 0.889729
+vt 0.036166 0.194032
+vt 0.127046 0.537243
+vt 0.260428 0.863335
+vt 0.116615 0.478315
+vt 0.213639 0.819179
+vt 0.105914 0.419482
+vt 0.184737 0.767195
+vt 0.495265 0.852856
+vt 0.995265 0.147143
+vt 1.032175 0.090357
+vt 1.058962 0.108237
+vt 1.067268 0.131697
+vt 1.063300 0.155685
+vt 1.051952 0.177121
+vt 0.427547 0.885321
+vt 1.036166 0.194032
+vt 0.031336 0.264931
+vt 0.017784 0.205113
+vn -0.629402 -0.766928 -0.125196
+vn -0.940062 0.285165 -0.186990
+vn -0.469338 -0.878070 -0.093357
+vn -0.976241 0.096152 -0.194186
+vn -0.289802 0.955349 -0.057645
+vn -0.289802 -0.955349 -0.057645
+vn -0.976241 -0.096151 -0.194186
+vn -0.469338 0.878070 -0.093357
+vn -0.940062 -0.285165 -0.186990
+vn -0.629402 0.766928 -0.125196
+vn -0.868657 -0.464306 -0.172787
+vn -0.764031 0.627024 -0.151975
+vn -0.764031 -0.627024 -0.151975
+vn -0.868657 0.464306 -0.172787
+vn -0.245682 -0.955349 -0.164159
+vn -0.827617 -0.096152 -0.552996
+vn -0.397886 0.878069 -0.265859
+vn -0.796946 -0.285165 -0.532502
+vn -0.533581 0.766929 -0.356527
+vn -0.736412 -0.464306 -0.492055
+vn -0.647715 0.627024 -0.432789
+vn -0.647714 -0.627024 -0.432789
+vn -0.736412 0.464306 -0.492055
+vn -0.533581 -0.766928 -0.356528
+vn -0.796946 0.285165 -0.532502
+vn -0.397886 -0.878070 -0.265859
+vn -0.827617 0.096152 -0.552996
+vn -0.245682 0.955349 -0.164160
+vn -0.356527 -0.766928 -0.533581
+vn -0.532502 0.285165 -0.796946
+vn -0.265859 -0.878070 -0.397886
+vn -0.552996 0.096152 -0.827617
+vn -0.164160 0.955349 -0.245682
+vn -0.164159 -0.955349 -0.245682
+vn -0.552996 -0.096152 -0.827617
+vn -0.265859 0.878069 -0.397886
+vn -0.532502 -0.285165 -0.796946
+vn -0.356527 0.766929 -0.533581
+vn -0.492054 -0.464306 -0.736412
+vn -0.432789 0.627024 -0.647715
+vn -0.432789 -0.627024 -0.647715
+vn -0.492054 0.464306 -0.736412
+vn -0.172786 -0.464306 -0.868657
+vn -0.151975 0.627024 -0.764032
+vn -0.151975 -0.627024 -0.764032
+vn -0.172786 0.464306 -0.868657
+vn -0.125196 -0.766928 -0.629402
+vn -0.186990 0.285165 -0.940062
+vn -0.093357 -0.878070 -0.469338
+vn -0.194186 0.096152 -0.976241
+vn -0.057645 0.955349 -0.289802
+vn -0.057645 -0.955349 -0.289801
+vn -0.194186 -0.096152 -0.976241
+vn -0.093357 0.878069 -0.469338
+vn -0.186990 -0.285165 -0.940062
+vn -0.125196 0.766929 -0.629402
+vn 0.057645 -0.955349 -0.289801
+vn 0.194186 -0.096152 -0.976241
+vn 0.093357 0.878069 -0.469338
+vn 0.186990 -0.285165 -0.940062
+vn 0.125196 0.766929 -0.629402
+vn 0.172787 -0.464306 -0.868657
+vn 0.151975 0.627024 -0.764031
+vn 0.151975 -0.627024 -0.764031
+vn 0.172787 0.464306 -0.868657
+vn 0.125196 -0.766928 -0.629402
+vn 0.186990 0.285165 -0.940062
+vn 0.093357 -0.878070 -0.469338
+vn 0.194186 0.096152 -0.976241
+vn 0.057645 0.955349 -0.289802
+vn 0.356528 -0.766928 -0.533581
+vn 0.532502 0.285165 -0.796946
+vn 0.265859 -0.878070 -0.397886
+vn 0.552996 0.096152 -0.827617
+vn 0.164160 0.955349 -0.245682
+vn 0.164159 -0.955349 -0.245682
+vn 0.552996 -0.096152 -0.827617
+vn 0.265859 0.878069 -0.397886
+vn 0.532502 -0.285165 -0.796946
+vn 0.356527 0.766929 -0.533581
+vn 0.492055 -0.464306 -0.736412
+vn 0.432789 0.627024 -0.647715
+vn 0.432789 -0.627024 -0.647714
+vn 0.492055 0.464306 -0.736412
+vn 0.736412 -0.464306 -0.492055
+vn 0.647715 0.627024 -0.432789
+vn 0.647715 -0.627024 -0.432789
+vn 0.736412 0.464306 -0.492054
+vn 0.533581 -0.766928 -0.356528
+vn 0.796946 0.285165 -0.532502
+vn 0.397886 -0.878070 -0.265859
+vn 0.827617 0.096152 -0.552996
+vn 0.245682 0.955349 -0.164160
+vn 0.245682 -0.955349 -0.164159
+vn 0.827617 -0.096152 -0.552996
+vn 0.397886 0.878069 -0.265859
+vn 0.796946 -0.285165 -0.532502
+vn 0.533581 0.766929 -0.356527
+vn 0.289802 0.955349 -0.057645
+vn 0.289801 -0.955349 -0.057645
+vn 0.976241 -0.096152 -0.194186
+vn 0.469338 0.878069 -0.093357
+vn 0.940062 -0.285165 -0.186990
+vn 0.629402 0.766929 -0.125196
+vn 0.868657 -0.464306 -0.172786
+vn 0.764032 0.627024 -0.151975
+vn 0.764032 -0.627024 -0.151975
+vn 0.868657 0.464307 -0.172786
+vn 0.629402 -0.766928 -0.125196
+vn 0.940062 0.285165 -0.186990
+vn 0.469338 -0.878069 -0.093357
+vn 0.976241 0.096152 -0.194186
+vn 0.868657 0.464306 0.172787
+vn 0.629402 -0.766928 0.125196
+vn 0.940062 0.285165 0.186990
+vn 0.469338 -0.878069 0.093357
+vn 0.976241 0.096152 0.194186
+vn 0.289802 0.955349 0.057645
+vn 0.289801 -0.955349 0.057645
+vn 0.976241 -0.096152 0.194187
+vn 0.469338 0.878069 0.093357
+vn 0.940061 -0.285165 0.186990
+vn 0.629402 0.766929 0.125196
+vn 0.868657 -0.464306 0.172787
+vn 0.764032 0.627024 0.151975
+vn 0.764032 -0.627024 0.151976
+vn 0.796946 -0.285165 0.532502
+vn 0.533581 0.766929 0.356527
+vn 0.736412 -0.464306 0.492055
+vn 0.647715 0.627024 0.432789
+vn 0.647715 -0.627024 0.432789
+vn 0.736411 0.464307 0.492054
+vn 0.533581 -0.766928 0.356528
+vn 0.796946 0.285165 0.532502
+vn 0.397886 -0.878070 0.265859
+vn 0.827617 0.096151 0.552996
+vn 0.245682 0.955349 0.164160
+vn 0.245682 -0.955349 0.164159
+vn 0.827617 -0.096151 0.552996
+vn 0.397886 0.878070 0.265859
+vn 0.265859 -0.878070 0.397886
+vn 0.552996 0.096151 0.827617
+vn 0.164160 0.955349 0.245682
+vn 0.164159 -0.955349 0.245682
+vn 0.552996 -0.096151 0.827617
+vn 0.265859 0.878070 0.397886
+vn 0.532502 -0.285165 0.796946
+vn 0.356527 0.766929 0.533581
+vn 0.492054 -0.464306 0.736412
+vn 0.432789 0.627024 0.647715
+vn 0.432789 -0.627024 0.647715
+vn 0.492054 0.464307 0.736412
+vn 0.356528 -0.766928 0.533581
+vn 0.532502 0.285165 0.796946
+vn 0.151975 -0.627024 0.764032
+vn 0.172786 0.464307 0.868656
+vn 0.125196 -0.766928 0.629402
+vn 0.186990 0.285165 0.940062
+vn 0.093357 -0.878070 0.469338
+vn 0.194186 0.096151 0.976241
+vn 0.057645 0.955349 0.289802
+vn 0.057645 -0.955349 0.289801
+vn 0.194186 -0.096151 0.976241
+vn 0.093357 0.878070 0.469338
+vn 0.186990 -0.285166 0.940061
+vn 0.125196 0.766929 0.629402
+vn 0.172786 -0.464306 0.868657
+vn 0.151975 0.627023 0.764032
+vn -0.186990 -0.285166 0.940061
+vn -0.125196 0.766929 0.629402
+vn -0.172787 -0.464306 0.868657
+vn -0.151976 0.627023 0.764032
+vn -0.151975 -0.627024 0.764032
+vn -0.172787 0.464307 0.868656
+vn -0.125196 -0.766928 0.629402
+vn -0.186990 0.285165 0.940062
+vn -0.093357 -0.878069 0.469338
+vn -0.194186 0.096151 0.976241
+vn -0.057645 0.955349 0.289802
+vn -0.057645 -0.955349 0.289801
+vn -0.194186 -0.096151 0.976241
+vn -0.093357 0.878069 0.469338
+vn -0.265859 -0.878070 0.397886
+vn -0.552996 0.096151 0.827617
+vn -0.164160 0.955349 0.245682
+vn -0.164159 -0.955349 0.245682
+vn -0.552996 -0.096151 0.827617
+vn -0.265859 0.878070 0.397886
+vn -0.532502 -0.285166 0.796945
+vn -0.356527 0.766929 0.533581
+vn -0.492054 -0.464306 0.736412
+vn -0.432790 0.627023 0.647715
+vn -0.432789 -0.627024 0.647715
+vn -0.492054 0.464307 0.736411
+vn -0.356528 -0.766928 0.533581
+vn -0.532502 0.285165 0.796946
+vn -0.647715 -0.627024 0.432789
+vn -0.736411 0.464307 0.492054
+vn -0.533581 -0.766928 0.356528
+vn -0.796946 0.285165 0.532502
+vn -0.397886 -0.878070 0.265859
+vn -0.827617 0.096151 0.552996
+vn -0.245682 0.955349 0.164160
+vn -0.245682 -0.955349 0.164159
+vn -0.827617 -0.096151 0.552996
+vn -0.397886 0.878070 0.265859
+vn -0.796946 -0.285166 0.532502
+vn -0.533581 0.766929 0.356527
+vn -0.736412 -0.464306 0.492054
+vn -0.647715 0.627023 0.432789
+vn -0.097999 0.994996 -0.019493
+vn -0.097998 -0.994996 -0.019493
+vn -0.083079 -0.994996 -0.055512
+vn -0.083079 0.994996 -0.055512
+vn -0.055512 0.994996 -0.083079
+vn -0.055512 -0.994996 -0.083079
+vn -0.019493 0.994996 -0.097998
+vn -0.019493 -0.994996 -0.097998
+vn 0.019493 -0.994996 -0.097998
+vn 0.019493 0.994996 -0.097998
+vn 0.055512 0.994996 -0.083079
+vn 0.055512 -0.994996 -0.083079
+vn 0.083079 0.994996 -0.055512
+vn 0.083079 -0.994996 -0.055512
+vn 0.097998 -0.994996 -0.019493
+vn 0.097998 0.994996 -0.019493
+vn 0.097998 0.994996 0.019493
+vn 0.097998 -0.994996 0.019493
+vn 0.083079 0.994996 0.055512
+vn 0.083079 -0.994996 0.055512
+vn 0.055512 -0.994996 0.083079
+vn 0.055512 0.994996 0.083079
+vn 0.019493 0.994996 0.097999
+vn 0.019493 -0.994996 0.097998
+vn -0.019493 -0.994996 0.097998
+vn -0.019493 0.994996 0.097999
+vn -0.055512 -0.994996 0.083079
+vn -0.055512 0.994996 0.083079
+vn -0.083079 0.994996 0.055512
+vn -0.083079 -0.994996 0.055512
+vn -0.097998 -0.994996 0.019493
+vn -0.940061 -0.285166 0.186991
+vn -0.629402 0.766929 0.125196
+vn -0.868656 -0.464306 0.172788
+vn -0.764032 0.627023 0.151977
+vn -0.764032 -0.627024 0.151976
+vn -0.868656 0.464307 0.172787
+vn -0.629402 -0.766928 0.125196
+vn -0.940061 0.285165 0.186990
+vn -0.097999 0.994996 0.019493
+vn -0.469338 -0.878070 0.093357
+vn -0.976241 0.096151 0.194187
+vn -0.289802 0.955349 0.057646
+vn -0.289801 -0.955349 0.057645
+vn -0.976241 -0.096151 0.194187
+vn -0.469338 0.878070 0.093358
+vn -0.976241 -0.096152 -0.194186
+vn -0.469338 0.878069 -0.093357
+vn -0.629401 0.766929 -0.125196
+vn -0.764032 0.627024 -0.151975
+vn -0.736411 -0.464306 -0.492055
+vn -0.736411 0.464306 -0.492055
+vn -0.356528 -0.766928 -0.533581
+vn -0.151975 -0.627024 -0.764031
+vn -0.194186 -0.096151 -0.976241
+vn 0.186990 -0.285165 -0.940061
+vn 0.151975 0.627024 -0.764032
+vn 0.432789 -0.627024 -0.647715
+vn 0.492055 0.464306 -0.736411
+vn 0.736412 -0.464306 -0.492054
+vn 0.736411 0.464307 -0.492054
+vn 0.976241 -0.096151 -0.194186
+vn 0.940062 -0.285166 -0.186990
+vn 0.868657 -0.464306 -0.172787
+vn 0.868657 0.464306 -0.172786
+vn 0.940061 0.285165 -0.186990
+vn 0.868656 0.464307 0.172787
+vn 0.976241 0.096151 0.194187
+vn 0.976241 -0.096151 0.194186
+vn 0.469338 0.878070 0.093357
+vn 0.940061 -0.285166 0.186990
+vn 0.764032 0.627024 0.151976
+vn 0.764032 -0.627024 0.151975
+vn 0.796945 -0.285166 0.532502
+vn 0.647715 0.627023 0.432790
+vn 0.736411 0.464307 0.492055
+vn 0.532502 -0.285166 0.796946
+vn 0.432789 0.627023 0.647715
+vn 0.492054 0.464307 0.736411
+vn 0.151975 -0.627023 0.764032
+vn 0.186990 0.285165 0.940061
+vn 0.093357 0.878069 0.469338
+vn -0.151975 0.627023 0.764032
+vn -0.151976 -0.627023 0.764032
+vn -0.186990 0.285165 0.940061
+vn -0.093357 -0.878070 0.469338
+vn -0.093357 0.878070 0.469338
+vn -0.532502 -0.285166 0.796946
+vn -0.492055 -0.464306 0.736412
+vn -0.432789 -0.627023 0.647715
+vn -0.647715 -0.627023 0.432789
+vn -0.796945 -0.285166 0.532502
+vn -0.647715 0.627023 0.432790
+vn -0.940062 -0.285165 0.186990
+vn -0.629402 0.766928 0.125196
+vn -0.764031 0.627024 0.151975
+vn -0.764031 -0.627024 0.151976
+vn -0.868657 0.464306 0.172788
+vn -0.940062 0.285165 0.186991
+vn -0.976241 0.096152 0.194187
+vn -0.289802 -0.955349 0.057645
+s off
+f 13/1/1 12/2/1 28/3/1
+f 7/4/2 6/5/2 22/6/2
+f 14/7/3 13/8/3 29/9/3
+f 8/10/4 7/4/4 23/11/4
+f 2/12/5 1/13/5 17/14/5
+f 15/15/6 14/7/6 30/16/6
+f 9/17/7 8/10/7 24/18/7
+f 3/19/8 2/12/8 18/20/8
+f 10/21/9 9/17/9 25/22/9
+f 4/23/10 3/19/10 19/24/10
+f 11/25/11 10/21/11 26/26/11
+f 5/27/12 4/23/12 20/28/12
+f 12/2/13 11/25/13 27/29/13
+f 6/5/14 5/27/14 21/30/14
+f 30/16/15 29/9/15 46/31/15
+f 24/32/16 23/33/16 40/34/16
+f 18/35/17 17/14/17 34/36/17
+f 25/37/18 24/32/18 41/38/18
+f 19/39/19 18/35/19 35/40/19
+f 26/41/20 25/37/20 42/42/20
+f 20/43/21 19/39/21 36/44/21
+f 27/45/22 26/41/22 43/46/22
+f 21/47/23 20/43/23 37/48/23
+f 28/49/24 27/45/24 44/50/24
+f 22/51/25 21/47/25 38/52/25
+f 29/9/26 28/49/26 45/53/26
+f 23/33/27 22/51/27 39/54/27
+f 17/14/28 16/55/28 33/56/28
+f 44/50/29 43/46/29 59/57/29
+f 38/52/30 37/48/30 53/58/30
+f 45/53/31 44/50/31 60/59/31
+f 39/54/32 38/52/32 54/60/32
+f 33/56/33 32/61/33 48/62/33
+f 46/31/34 45/53/34 61/63/34
+f 40/34/35 39/54/35 55/64/35
+f 34/36/36 33/56/36 49/65/36
+f 41/38/37 40/34/37 56/66/37
+f 35/40/38 34/36/38 50/67/38
+f 42/42/39 41/38/39 57/68/39
+f 36/44/40 35/40/40 51/69/40
+f 43/46/41 42/42/41 58/70/41
+f 37/48/42 36/44/42 52/71/42
+f 57/68/43 56/66/43 72/72/43
+f 51/69/44 50/67/44 66/73/44
+f 58/70/45 57/68/45 73/74/45
+f 52/71/46 51/69/46 67/75/46
+f 59/57/47 58/70/47 74/76/47
+f 53/58/48 52/71/48 68/77/48
+f 60/59/49 59/57/49 75/78/49
+f 54/60/50 53/58/50 69/79/50
+f 48/62/51 47/80/51 63/81/51
+f 61/63/52 60/59/52 76/82/52
+f 55/64/53 54/60/53 70/83/53
+f 49/65/54 48/62/54 64/84/54
+f 56/66/55 55/64/55 71/85/55
+f 50/67/56 49/65/56 65/86/56
+f 76/82/57 75/78/57 90/87/57
+f 70/83/58 69/79/58 84/88/58
+f 64/84/59 63/81/59 78/89/59
+f 71/85/60 70/83/60 85/90/60
+f 65/86/61 64/84/61 79/91/61
+f 72/72/62 71/85/62 86/92/62
+f 66/73/63 65/86/63 80/93/63
+f 73/74/64 72/72/64 87/94/64
+f 67/75/65 66/73/65 81/95/65
+f 74/76/66 73/74/66 88/96/66
+f 68/77/67 67/75/67 82/97/67
+f 75/78/68 74/76/68 89/98/68
+f 69/79/69 68/77/69 83/99/69
+f 63/81/70 62/100/70 77/101/70
+f 89/98/71 88/96/71 103/102/71
+f 83/99/72 82/97/72 97/103/72
+f 90/87/73 89/98/73 104/104/73
+f 84/88/74 83/99/74 98/105/74
+f 78/89/75 77/101/75 92/106/75
+f 91/107/76 90/87/76 105/108/76
+f 85/90/77 84/88/77 99/109/77
+f 79/91/78 78/89/78 93/110/78
+f 86/92/79 85/90/79 100/111/79
+f 80/93/80 79/91/80 94/112/80
+f 87/94/81 86/92/81 101/113/81
+f 81/95/82 80/93/82 95/114/82
+f 88/96/83 87/94/83 102/115/83
+f 82/97/84 81/95/84 96/116/84
+f 102/115/85 101/113/85 116/117/85
+f 96/116/86 95/114/86 110/118/86
+f 103/102/87 102/115/87 117/119/87
+f 97/103/88 96/116/88 111/120/88
+f 104/104/89 103/102/89 118/121/89
+f 98/105/90 97/103/90 112/122/90
+f 105/108/91 104/104/91 119/123/91
+f 99/109/92 98/105/92 113/124/92
+f 93/110/93 92/106/93 107/125/93
+f 106/126/94 105/108/94 120/127/94
+f 100/111/95 99/109/95 114/128/95
+f 94/112/96 93/110/96 108/129/96
+f 101/113/97 100/111/97 115/130/97
+f 95/114/98 94/112/98 109/131/98
+f 108/129/99 107/125/99 122/132/99
+f 121/133/100 120/127/100 135/134/100
+f 115/130/101 114/128/101 129/135/101
+f 109/131/102 108/129/102 123/136/102
+f 116/117/103 115/130/103 130/137/103
+f 110/118/104 109/131/104 124/138/104
+f 117/119/105 116/117/105 131/139/105
+f 111/120/106 110/118/106 125/140/106
+f 118/121/107 117/119/107 132/141/107
+f 112/122/108 111/120/108 126/142/108
+f 119/123/109 118/121/109 133/143/109
+f 113/124/110 112/122/110 127/144/110
+f 120/127/111 119/123/111 134/145/111
+f 114/128/112 113/124/112 128/146/112
+f 127/144/113 126/142/113 141/147/113
+f 134/145/114 133/143/114 148/148/114
+f 128/146/115 127/144/115 142/149/115
+f 135/134/116 134/145/116 149/150/116
+f 129/135/117 128/146/117 143/151/117
+f 123/136/118 122/132/118 137/152/118
+f 136/153/119 135/134/119 150/154/119
+f 130/137/120 129/135/120 144/155/120
+f 124/138/121 123/136/121 138/156/121
+f 131/139/122 130/137/122 145/157/122
+f 125/140/123 124/138/123 139/158/123
+f 132/141/124 131/139/124 146/159/124
+f 126/142/125 125/140/125 140/160/125
+f 133/143/126 132/141/126 147/161/126
+f 146/159/127 145/157/127 160/162/127
+f 140/160/128 139/158/128 154/163/128
+f 147/161/129 146/159/129 161/164/129
+f 141/147/130 140/160/130 155/165/130
+f 148/148/131 147/161/131 162/166/131
+f 142/149/132 141/147/132 157/167/132
+f 149/150/133 148/148/133 163/168/133
+f 143/151/134 142/149/134 157/167/134
+f 150/154/135 149/150/135 164/169/135
+f 144/155/136 143/151/136 158/170/136
+f 138/156/137 137/152/137 152/171/137
+f 151/172/138 150/154/138 165/173/138
+f 145/157/139 144/155/139 159/174/139
+f 139/158/140 138/156/140 153/175/140
+f 165/176/141 164/177/141 179/178/141
+f 159/174/142 158/170/142 173/179/142
+f 153/175/143 152/171/143 167/180/143
+f 166/181/144 165/176/144 180/182/144
+f 160/162/145 159/174/145 174/183/145
+f 154/163/146 153/175/146 168/184/146
+f 161/164/147 160/162/147 175/185/147
+f 155/165/148 154/163/148 169/186/148
+f 162/166/149 161/164/149 176/187/149
+f 156/188/150 155/165/150 170/189/150
+f 163/168/151 162/166/151 177/190/151
+f 157/167/152 156/188/152 171/191/152
+f 164/177/153 163/168/153 178/192/153
+f 158/170/154 157/167/154 172/193/154
+f 178/192/155 177/190/155 192/194/155
+f 172/193/156 171/191/156 186/195/156
+f 179/178/157 178/192/157 193/196/157
+f 173/179/158 172/193/158 187/197/158
+f 180/182/159 179/178/159 194/198/159
+f 174/183/160 173/179/160 188/199/160
+f 168/184/161 167/180/161 182/200/161
+f 181/201/162 180/182/162 195/202/162
+f 175/185/163 174/183/163 189/203/163
+f 169/186/164 168/184/164 183/204/164
+f 176/187/165 175/185/165 190/205/165
+f 170/189/166 169/186/166 184/206/166
+f 177/190/167 176/187/167 191/207/167
+f 171/191/168 170/189/168 185/208/168
+f 191/207/169 190/205/169 206/209/169
+f 185/208/170 184/206/170 200/210/170
+f 192/194/171 191/207/171 207/211/171
+f 186/195/172 185/208/172 201/212/172
+f 193/196/173 192/194/173 208/213/173
+f 187/197/174 186/195/174 202/214/174
+f 194/198/175 193/196/175 209/215/175
+f 188/199/176 187/197/176 203/216/176
+f 195/202/177 194/198/177 210/217/177
+f 189/203/178 188/199/178 204/218/178
+f 183/204/179 182/200/179 198/219/179
+f 196/220/180 195/202/180 211/221/180
+f 190/205/181 189/203/181 205/222/181
+f 184/206/182 183/204/182 199/223/182
+f 210/217/183 209/215/183 226/224/183
+f 204/218/184 203/216/184 220/225/184
+f 198/219/185 197/226/185 214/227/185
+f 211/221/186 210/217/186 227/228/186
+f 205/222/187 204/218/187 221/229/187
+f 199/223/188 198/219/188 215/230/188
+f 206/209/189 205/222/189 222/231/189
+f 200/210/190 199/223/190 216/232/190
+f 207/211/191 206/209/191 223/233/191
+f 201/212/192 200/210/192 217/234/192
+f 208/213/193 207/211/193 223/233/193
+f 202/214/194 201/212/194 218/235/194
+f 209/215/195 208/213/195 225/236/195
+f 203/216/196 202/214/196 219/237/196
+f 224/238/197 223/233/197 239/239/197
+f 218/235/198 217/234/198 233/240/198
+f 225/236/199 224/238/199 240/241/199
+f 219/237/200 218/235/200 234/242/200
+f 226/224/201 225/236/201 241/243/201
+f 220/225/202 219/237/202 235/244/202
+f 214/227/203 213/245/203 229/246/203
+f 227/228/204 226/224/204 242/247/204
+f 221/229/205 220/225/205 236/248/205
+f 215/230/206 214/227/206 230/249/206
+f 222/231/207 221/229/207 237/250/207
+f 216/232/208 215/230/208 231/251/208
+f 223/233/209 222/231/209 238/252/209
+f 217/234/210 216/232/210 232/253/210
+f 1/13/211 212/254/211 16/55/211
+f 31/255/212 15/15/212 30/16/212
+f 31/255/213 30/16/213 46/31/213
+f 16/55/214 212/254/214 32/61/214
+f 32/61/215 212/254/215 47/80/215
+f 31/255/216 46/31/216 61/63/216
+f 47/80/217 212/254/217 62/100/217
+f 31/255/218 61/63/218 76/82/218
+f 31/255/219 76/82/219 91/107/219
+f 62/100/220 212/254/220 77/101/220
+f 77/101/221 212/254/221 92/106/221
+f 31/255/222 91/107/222 106/126/222
+f 92/106/223 212/254/223 107/125/223
+f 31/255/224 106/126/224 121/133/224
+f 31/255/225 121/133/225 136/153/225
+f 107/125/226 212/254/226 122/132/226
+f 122/132/227 212/254/227 137/152/227
+f 31/255/228 136/153/228 151/172/228
+f 137/152/229 212/254/229 152/171/229
+f 31/255/230 151/172/230 166/256/230
+f 31/255/231 166/256/231 181/257/231
+f 152/171/232 212/254/232 167/180/232
+f 167/180/233 212/254/233 182/200/233
+f 31/255/234 181/257/234 196/258/234
+f 31/255/235 196/258/235 211/259/235
+f 182/200/236 212/254/236 197/226/236
+f 31/255/237 211/259/237 227/260/237
+f 197/226/238 212/254/238 213/245/238
+f 213/245/239 212/254/239 228/261/239
+f 31/255/240 227/260/240 242/262/240
+f 31/255/241 242/262/241 15/15/241
+f 237/250/242 236/248/242 10/21/242
+f 231/251/243 230/249/243 4/23/243
+f 238/252/244 237/250/244 10/21/244
+f 232/253/245 231/251/245 5/27/245
+f 239/239/246 238/252/246 11/25/246
+f 233/240/247 232/253/247 6/5/247
+f 240/241/248 239/239/248 13/1/248
+f 234/242/249 233/240/249 7/4/249
+f 228/261/250 212/254/250 1/13/250
+f 241/243/251 240/241/251 14/263/251
+f 235/244/252 234/242/252 8/10/252
+f 229/246/253 228/261/253 2/12/253
+f 242/247/254 241/243/254 15/264/254
+f 236/248/255 235/244/255 9/17/255
+f 230/249/256 229/246/256 3/19/256
+f 12/2/1 27/29/1 28/3/1
+f 6/5/2 21/30/2 22/6/2
+f 13/8/3 28/49/3 29/9/3
+f 7/4/4 22/6/4 23/11/4
+f 1/13/5 16/55/5 17/14/5
+f 14/7/6 29/9/6 30/16/6
+f 8/10/257 23/11/257 24/18/257
+f 2/12/258 17/14/258 18/20/258
+f 9/17/9 24/18/9 25/22/9
+f 3/19/259 18/20/259 19/24/259
+f 10/21/11 25/22/11 26/26/11
+f 4/23/260 19/24/260 20/28/260
+f 11/25/13 26/26/13 27/29/13
+f 5/27/14 20/28/14 21/30/14
+f 29/9/15 45/53/15 46/31/15
+f 23/33/16 39/54/16 40/34/16
+f 17/14/17 33/56/17 34/36/17
+f 24/32/18 40/34/18 41/38/18
+f 18/35/19 34/36/19 35/40/19
+f 25/37/261 41/38/261 42/42/261
+f 19/39/21 35/40/21 36/44/21
+f 26/41/22 42/42/22 43/46/22
+f 20/43/262 36/44/262 37/48/262
+f 27/45/24 43/46/24 44/50/24
+f 21/47/25 37/48/25 38/52/25
+f 28/49/26 44/50/26 45/53/26
+f 22/51/27 38/52/27 39/54/27
+f 16/55/28 32/61/28 33/56/28
+f 43/46/263 58/70/263 59/57/263
+f 37/48/30 52/71/30 53/58/30
+f 44/50/31 59/57/31 60/59/31
+f 38/52/32 53/58/32 54/60/32
+f 32/61/33 47/80/33 48/62/33
+f 45/53/34 60/59/34 61/63/34
+f 39/54/35 54/60/35 55/64/35
+f 33/56/36 48/62/36 49/65/36
+f 40/34/37 55/64/37 56/66/37
+f 34/36/38 49/65/38 50/67/38
+f 41/38/39 56/66/39 57/68/39
+f 35/40/40 50/67/40 51/69/40
+f 42/42/41 57/68/41 58/70/41
+f 36/44/42 51/69/42 52/71/42
+f 56/66/43 71/85/43 72/72/43
+f 50/67/44 65/86/44 66/73/44
+f 57/68/264 72/72/264 73/74/264
+f 51/69/46 66/73/46 67/75/46
+f 58/70/47 73/74/47 74/76/47
+f 52/71/48 67/75/48 68/77/48
+f 59/57/49 74/76/49 75/78/49
+f 53/58/50 68/77/50 69/79/50
+f 47/80/51 62/100/51 63/81/51
+f 60/59/52 75/78/52 76/82/52
+f 54/60/265 69/79/265 70/83/265
+f 48/62/54 63/81/54 64/84/54
+f 55/64/55 70/83/55 71/85/55
+f 49/65/56 64/84/56 65/86/56
+f 91/107/57 76/82/57 90/87/57
+f 85/90/58 70/83/58 84/88/58
+f 79/91/59 64/84/59 78/89/59
+f 86/92/266 71/85/266 85/90/266
+f 80/93/61 65/86/61 79/91/61
+f 87/94/62 72/72/62 86/92/62
+f 81/95/267 66/73/267 80/93/267
+f 88/96/64 73/74/64 87/94/64
+f 82/97/65 67/75/65 81/95/65
+f 89/98/66 74/76/66 88/96/66
+f 83/99/67 68/77/67 82/97/67
+f 90/87/68 75/78/68 89/98/68
+f 84/88/69 69/79/69 83/99/69
+f 78/89/70 63/81/70 77/101/70
+f 104/104/71 89/98/71 103/102/71
+f 98/105/72 83/99/72 97/103/72
+f 105/108/73 90/87/73 104/104/73
+f 99/109/74 84/88/74 98/105/74
+f 93/110/75 78/89/75 92/106/75
+f 106/126/76 91/107/76 105/108/76
+f 100/111/77 85/90/77 99/109/77
+f 94/112/78 79/91/78 93/110/78
+f 101/113/79 86/92/79 100/111/79
+f 95/114/80 80/93/80 94/112/80
+f 102/115/81 87/94/81 101/113/81
+f 96/116/82 81/95/82 95/114/82
+f 103/102/268 88/96/268 102/115/268
+f 97/103/269 82/97/269 96/116/269
+f 117/119/270 102/115/270 116/117/270
+f 111/120/86 96/116/86 110/118/86
+f 118/121/87 103/102/87 117/119/87
+f 112/122/271 97/103/271 111/120/271
+f 119/123/89 104/104/89 118/121/89
+f 113/124/90 98/105/90 112/122/90
+f 120/127/91 105/108/91 119/123/91
+f 114/128/92 99/109/92 113/124/92
+f 108/129/93 93/110/93 107/125/93
+f 121/133/94 106/126/94 120/127/94
+f 115/130/95 100/111/95 114/128/95
+f 109/131/96 94/112/96 108/129/96
+f 116/117/97 101/113/97 115/130/97
+f 110/118/98 95/114/98 109/131/98
+f 123/136/99 108/129/99 122/132/99
+f 136/153/100 121/133/100 135/134/100
+f 130/137/272 115/130/272 129/135/272
+f 124/138/102 109/131/102 123/136/102
+f 131/139/273 116/117/273 130/137/273
+f 125/140/104 110/118/104 124/138/104
+f 132/141/274 117/119/274 131/139/274
+f 126/142/106 111/120/106 125/140/106
+f 133/143/107 118/121/107 132/141/107
+f 127/144/275 112/122/275 126/142/275
+f 134/145/109 119/123/109 133/143/109
+f 128/146/276 113/124/276 127/144/276
+f 135/134/111 120/127/111 134/145/111
+f 129/135/112 114/128/112 128/146/112
+f 142/149/277 127/144/277 141/147/277
+f 149/150/114 134/145/114 148/148/114
+f 143/151/115 128/146/115 142/149/115
+f 150/154/116 135/134/116 149/150/116
+f 144/155/278 129/135/278 143/151/278
+f 138/156/118 123/136/118 137/152/118
+f 151/172/119 136/153/119 150/154/119
+f 145/157/279 130/137/279 144/155/279
+f 139/158/280 124/138/280 138/156/280
+f 146/159/281 131/139/281 145/157/281
+f 140/160/123 125/140/123 139/158/123
+f 147/161/124 132/141/124 146/159/124
+f 141/147/282 126/142/282 140/160/282
+f 148/148/283 133/143/283 147/161/283
+f 161/164/284 146/159/284 160/162/284
+f 155/165/128 140/160/128 154/163/128
+f 162/166/129 147/161/129 161/164/129
+f 156/188/285 141/147/285 155/165/285
+f 163/168/131 148/148/131 162/166/131
+f 141/147/286 156/188/286 157/167/286
+f 164/177/133 149/150/133 163/168/133
+f 158/170/134 143/151/134 157/167/134
+f 165/173/135 150/154/135 164/169/135
+f 159/174/136 144/155/136 158/170/136
+f 153/175/137 138/156/137 152/171/137
+f 166/256/138 151/172/138 165/173/138
+f 160/162/139 145/157/139 159/174/139
+f 154/163/140 139/158/140 153/175/140
+f 180/182/141 165/176/141 179/178/141
+f 174/183/142 159/174/142 173/179/142
+f 168/184/143 153/175/143 167/180/143
+f 181/201/144 166/181/144 180/182/144
+f 175/185/145 160/162/145 174/183/145
+f 169/186/146 154/163/146 168/184/146
+f 176/187/287 161/164/287 175/185/287
+f 170/189/148 155/165/148 169/186/148
+f 177/190/149 162/166/149 176/187/149
+f 171/191/288 156/188/288 170/189/288
+f 178/192/151 163/168/151 177/190/151
+f 172/193/289 157/167/289 171/191/289
+f 179/178/153 164/177/153 178/192/153
+f 173/179/154 158/170/154 172/193/154
+f 193/196/290 178/192/290 192/194/290
+f 187/197/156 172/193/156 186/195/156
+f 194/198/157 179/178/157 193/196/157
+f 188/199/291 173/179/291 187/197/291
+f 195/202/159 180/182/159 194/198/159
+f 189/203/160 174/183/160 188/199/160
+f 183/204/161 168/184/161 182/200/161
+f 196/220/162 181/201/162 195/202/162
+f 190/205/163 175/185/163 189/203/163
+f 184/206/292 169/186/292 183/204/292
+f 191/207/165 176/187/165 190/205/165
+f 185/208/166 170/189/166 184/206/166
+f 192/194/167 177/190/167 191/207/167
+f 186/195/168 171/191/168 185/208/168
+f 190/205/169 205/222/169 206/209/169
+f 184/206/170 199/223/170 200/210/170
+f 191/207/171 206/209/171 207/211/171
+f 185/208/293 200/210/293 201/212/293
+f 192/194/294 207/211/294 208/213/294
+f 186/195/174 201/212/174 202/214/174
+f 193/196/175 208/213/175 209/215/175
+f 187/197/295 202/214/295 203/216/295
+f 194/198/296 209/215/296 210/217/296
+f 188/199/178 203/216/178 204/218/178
+f 182/200/179 197/226/179 198/219/179
+f 195/202/180 210/217/180 211/221/180
+f 189/203/181 204/218/181 205/222/181
+f 183/204/297 198/219/297 199/223/297
+f 209/215/183 225/236/183 226/224/183
+f 203/216/184 219/237/184 220/225/184
+f 197/226/185 213/245/185 214/227/185
+f 210/217/186 226/224/186 227/228/186
+f 204/218/187 220/225/187 221/229/187
+f 198/219/188 214/227/188 215/230/188
+f 205/222/298 221/229/298 222/231/298
+f 199/223/190 215/230/190 216/232/190
+f 206/209/299 222/231/299 223/233/299
+f 200/210/192 216/232/192 217/234/192
+f 224/238/300 208/213/300 223/233/300
+f 201/212/194 217/234/194 218/235/194
+f 208/213/195 224/238/195 225/236/195
+f 202/214/196 218/235/196 219/237/196
+f 223/233/301 238/252/301 239/239/301
+f 217/234/198 232/253/198 233/240/198
+f 224/238/199 239/239/199 240/241/199
+f 218/235/200 233/240/200 234/242/200
+f 225/236/201 240/241/201 241/243/201
+f 219/237/202 234/242/202 235/244/202
+f 213/245/203 228/261/203 229/246/203
+f 226/224/204 241/243/204 242/247/204
+f 220/225/205 235/244/205 236/248/205
+f 214/227/206 229/246/206 230/249/206
+f 221/229/302 236/248/302 237/250/302
+f 215/230/208 230/249/208 231/251/208
+f 222/231/209 237/250/209 238/252/209
+f 216/232/303 231/251/303 232/253/303
+f 236/248/304 9/17/304 10/21/304
+f 230/249/305 3/19/305 4/23/305
+f 11/25/244 238/252/244 10/21/244
+f 231/251/306 4/23/306 5/27/306
+f 12/2/307 239/239/307 11/25/307
+f 232/253/308 5/27/308 6/5/308
+f 239/239/248 12/2/248 13/1/248
+f 233/240/309 6/5/309 7/4/309
+f 240/241/251 13/1/251 14/263/251
+f 234/242/310 7/4/310 8/10/310
+f 228/261/253 1/13/253 2/12/253
+f 241/243/311 14/263/311 15/264/311
+f 235/244/255 8/10/255 9/17/255
+f 229/246/256 2/12/256 3/19/256
diff --git a/src/datavis3d/engine/meshes/sphereSmooth.obj b/src/datavis3d/engine/meshes/sphereSmooth.obj
new file mode 100644
index 00000000..3c5b1299
--- /dev/null
+++ b/src/datavis3d/engine/meshes/sphereSmooth.obj
@@ -0,0 +1,1232 @@
+# Blender v2.66 (sub 0) OBJ File: 'sphere.blend'
+# www.blender.org
+o Sphere
+v -0.195090 0.980785 0.000000
+v -0.382683 0.923880 0.000000
+v -0.555570 0.831470 0.000000
+v -0.707107 0.707107 0.000000
+v -0.831470 0.555570 0.000000
+v -0.923880 0.382683 0.000000
+v -0.980785 0.195090 0.000000
+v -1.000000 0.000000 0.000000
+v -0.980785 -0.195090 0.000000
+v -0.923880 -0.382683 0.000000
+v -0.831470 -0.555570 0.000000
+v -0.707107 -0.707107 0.000000
+v -0.555570 -0.831470 0.000000
+v -0.382683 -0.923880 0.000000
+v -0.195090 -0.980785 0.000000
+v -0.180240 0.980785 -0.074658
+v -0.353553 0.923880 -0.146447
+v -0.513280 0.831470 -0.212608
+v -0.653281 0.707107 -0.270598
+v -0.768178 0.555570 -0.318190
+v -0.853553 0.382683 -0.353553
+v -0.906127 0.195090 -0.375330
+v -0.923880 0.000000 -0.382684
+v -0.906127 -0.195090 -0.375330
+v -0.853553 -0.382683 -0.353554
+v -0.768178 -0.555570 -0.318190
+v -0.653281 -0.707107 -0.270598
+v -0.513280 -0.831470 -0.212608
+v -0.353553 -0.923880 -0.146447
+v -0.180240 -0.980785 -0.074658
+v 0.000000 -1.000000 0.000000
+v -0.137950 0.980785 -0.137950
+v -0.270598 0.923880 -0.270598
+v -0.392847 0.831470 -0.392848
+v -0.500000 0.707107 -0.500000
+v -0.587938 0.555570 -0.587938
+v -0.653281 0.382683 -0.653282
+v -0.693520 0.195090 -0.693520
+v -0.707107 0.000000 -0.707107
+v -0.693520 -0.195090 -0.693520
+v -0.653281 -0.382683 -0.653282
+v -0.587938 -0.555570 -0.587938
+v -0.500000 -0.707107 -0.500000
+v -0.392847 -0.831470 -0.392848
+v -0.270598 -0.923880 -0.270598
+v -0.137949 -0.980785 -0.137950
+v -0.074658 0.980785 -0.180240
+v -0.146446 0.923880 -0.353554
+v -0.212607 0.831470 -0.513280
+v -0.270598 0.707107 -0.653282
+v -0.318189 0.555570 -0.768178
+v -0.353553 0.382683 -0.853554
+v -0.375330 0.195090 -0.906128
+v -0.382683 0.000000 -0.923880
+v -0.375330 -0.195090 -0.906128
+v -0.353553 -0.382683 -0.853554
+v -0.318189 -0.555570 -0.768178
+v -0.270598 -0.707107 -0.653282
+v -0.212607 -0.831470 -0.513280
+v -0.146446 -0.923880 -0.353554
+v -0.074658 -0.980785 -0.180240
+v 0.000000 0.980785 -0.195091
+v 0.000000 0.923880 -0.382684
+v 0.000000 0.831470 -0.555570
+v 0.000000 0.707107 -0.707107
+v 0.000000 0.555570 -0.831470
+v 0.000000 0.382683 -0.923880
+v 0.000000 0.195090 -0.980785
+v 0.000000 0.000000 -1.000000
+v 0.000000 -0.195090 -0.980785
+v 0.000000 -0.382683 -0.923880
+v 0.000000 -0.555570 -0.831470
+v 0.000000 -0.707107 -0.707107
+v 0.000000 -0.831470 -0.555570
+v 0.000000 -0.923880 -0.382684
+v 0.000000 -0.980785 -0.195090
+v 0.074658 0.980785 -0.180240
+v 0.146447 0.923880 -0.353554
+v 0.212608 0.831470 -0.513280
+v 0.270598 0.707107 -0.653282
+v 0.318190 0.555570 -0.768178
+v 0.353554 0.382683 -0.853553
+v 0.375331 0.195090 -0.906128
+v 0.382684 0.000000 -0.923880
+v 0.375331 -0.195090 -0.906128
+v 0.353554 -0.382683 -0.853553
+v 0.318190 -0.555570 -0.768178
+v 0.270598 -0.707107 -0.653282
+v 0.212608 -0.831470 -0.513280
+v 0.146447 -0.923880 -0.353554
+v 0.074658 -0.980785 -0.180240
+v 0.137950 0.980785 -0.137950
+v 0.270599 0.923880 -0.270598
+v 0.392848 0.831470 -0.392848
+v 0.500000 0.707107 -0.500000
+v 0.587938 0.555570 -0.587938
+v 0.653282 0.382683 -0.653282
+v 0.693520 0.195090 -0.693520
+v 0.707107 0.000000 -0.707107
+v 0.693520 -0.195090 -0.693520
+v 0.653282 -0.382683 -0.653281
+v 0.587938 -0.555570 -0.587938
+v 0.500000 -0.707107 -0.500000
+v 0.392848 -0.831470 -0.392848
+v 0.270599 -0.923880 -0.270598
+v 0.137950 -0.980785 -0.137950
+v 0.180241 0.980785 -0.074658
+v 0.353554 0.923880 -0.146447
+v 0.513280 0.831470 -0.212608
+v 0.653282 0.707107 -0.270598
+v 0.768178 0.555570 -0.318190
+v 0.853554 0.382683 -0.353553
+v 0.906128 0.195090 -0.375330
+v 0.923880 0.000000 -0.382683
+v 0.906128 -0.195090 -0.375330
+v 0.853554 -0.382683 -0.353553
+v 0.768178 -0.555570 -0.318190
+v 0.653282 -0.707107 -0.270598
+v 0.513280 -0.831470 -0.212608
+v 0.353554 -0.923880 -0.146447
+v 0.180240 -0.980785 -0.074658
+v 0.195091 0.980785 0.000000
+v 0.382684 0.923880 0.000000
+v 0.555571 0.831470 0.000000
+v 0.707107 0.707107 0.000000
+v 0.831470 0.555570 0.000000
+v 0.923880 0.382683 0.000000
+v 0.980786 0.195090 0.000000
+v 1.000000 0.000000 0.000000
+v 0.980786 -0.195090 0.000000
+v 0.923880 -0.382683 0.000000
+v 0.831470 -0.555570 0.000000
+v 0.707107 -0.707107 0.000000
+v 0.555571 -0.831470 0.000000
+v 0.382684 -0.923880 0.000000
+v 0.195091 -0.980785 0.000000
+v 0.180241 0.980785 0.074658
+v 0.353554 0.923880 0.146447
+v 0.513280 0.831470 0.212608
+v 0.653282 0.707107 0.270598
+v 0.768178 0.555570 0.318190
+v 0.853554 0.382683 0.353553
+v 0.906128 0.195090 0.375330
+v 0.923880 0.000000 0.382684
+v 0.906128 -0.195090 0.375330
+v 0.853554 -0.382683 0.353553
+v 0.768178 -0.555570 0.318190
+v 0.653282 -0.707107 0.270598
+v 0.513280 -0.831470 0.212608
+v 0.353554 -0.923880 0.146447
+v 0.180240 -0.980785 0.074658
+v 0.137950 0.980785 0.137950
+v 0.270599 0.923880 0.270598
+v 0.392848 0.831470 0.392848
+v 0.500000 0.707107 0.500000
+v 0.587938 0.555570 0.587938
+v 0.653282 0.382683 0.653282
+v 0.693520 0.195090 0.693520
+v 0.707107 0.000000 0.707107
+v 0.693520 -0.195090 0.693520
+v 0.653282 -0.382683 0.653282
+v 0.587938 -0.555570 0.587938
+v 0.500000 -0.707107 0.500000
+v 0.392848 -0.831470 0.392848
+v 0.270599 -0.923880 0.270598
+v 0.137950 -0.980785 0.137950
+v 0.074658 0.980785 0.180240
+v 0.146447 0.923880 0.353554
+v 0.212608 0.831470 0.513280
+v 0.270598 0.707107 0.653282
+v 0.318190 0.555570 0.768178
+v 0.353554 0.382683 0.853553
+v 0.375331 0.195090 0.906128
+v 0.382684 0.000000 0.923880
+v 0.375331 -0.195090 0.906128
+v 0.353554 -0.382683 0.853553
+v 0.318190 -0.555570 0.768178
+v 0.270598 -0.707107 0.653282
+v 0.212608 -0.831470 0.513280
+v 0.146447 -0.923880 0.353554
+v 0.074658 -0.980785 0.180240
+v 0.000000 0.980785 0.195091
+v 0.000000 0.923880 0.382684
+v 0.000000 0.831470 0.555570
+v 0.000000 0.707107 0.707107
+v 0.000000 0.555570 0.831470
+v 0.000000 0.382683 0.923880
+v 0.000000 0.195090 0.980785
+v 0.000000 0.000000 1.000000
+v 0.000000 -0.195090 0.980785
+v 0.000000 -0.382683 0.923879
+v 0.000000 -0.555570 0.831470
+v 0.000000 -0.707107 0.707107
+v 0.000000 -0.831470 0.555570
+v 0.000000 -0.923880 0.382684
+v 0.000000 -0.980785 0.195090
+v -0.074658 0.980785 0.180240
+v -0.146446 0.923880 0.353554
+v -0.212607 0.831470 0.513280
+v -0.270598 0.707107 0.653282
+v -0.318189 0.555570 0.768178
+v -0.353553 0.382683 0.853553
+v -0.375330 0.195090 0.906128
+v -0.382683 0.000000 0.923880
+v -0.375330 -0.195090 0.906128
+v -0.353553 -0.382683 0.853553
+v -0.318189 -0.555570 0.768178
+v -0.270598 -0.707107 0.653282
+v -0.212607 -0.831470 0.513280
+v -0.146446 -0.923880 0.353554
+v -0.074658 -0.980785 0.180240
+v 0.000000 1.000000 0.000000
+v -0.137950 0.980785 0.137950
+v -0.270598 0.923880 0.270598
+v -0.392847 0.831470 0.392848
+v -0.500000 0.707107 0.500000
+v -0.587938 0.555570 0.587938
+v -0.653281 0.382683 0.653281
+v -0.693520 0.195090 0.693520
+v -0.707107 0.000000 0.707107
+v -0.693520 -0.195090 0.693520
+v -0.653281 -0.382683 0.653281
+v -0.587938 -0.555570 0.587938
+v -0.500000 -0.707107 0.500000
+v -0.392847 -0.831470 0.392848
+v -0.270598 -0.923880 0.270598
+v -0.137949 -0.980785 0.137950
+v -0.180240 0.980785 0.074658
+v -0.353553 0.923880 0.146447
+v -0.513280 0.831470 0.212608
+v -0.653281 0.707107 0.270598
+v -0.768177 0.555570 0.318190
+v -0.853553 0.382683 0.353553
+v -0.906127 0.195090 0.375330
+v -0.923879 0.000000 0.382683
+v -0.906127 -0.195090 0.375330
+v -0.853553 -0.382683 0.353553
+v -0.768177 -0.555570 0.318190
+v -0.653281 -0.707107 0.270598
+v -0.513280 -0.831470 0.212608
+v -0.353553 -0.923880 0.146447
+v -0.180240 -0.980785 0.074658
+vt 0.040867 0.325557
+vt 0.048386 0.386583
+vt 0.001015 0.334499
+vt 0.081872 0.692529
+vt 0.092315 0.752973
+vt 0.006404 0.709363
+vt 1.031336 0.264931
+vt 1.040867 0.325557
+vt 0.999822 0.272029
+vt 0.073887 0.631595
+vt 0.005301 0.646891
+vt 0.333915 0.937286
+vt 0.448527 0.905466
+vt 0.447682 0.976645
+vt 1.017784 0.205113
+vt 0.998129 0.209571
+vt 0.067156 0.570413
+vt 0.004397 0.584414
+vt 0.196016 0.918498
+vt 0.034176 0.958662
+vt 0.060989 0.509119
+vt 0.003585 0.521934
+vt 0.135028 0.869370
+vt 0.015221 0.896641
+vt 0.054891 0.447811
+vt 0.002796 0.459454
+vt 0.107782 0.812401
+vt 0.010297 0.834265
+vt 0.001965 0.396975
+vt 0.007907 0.771825
+vt 0.978319 0.207096
+vt 1.004397 0.584414
+vt 1.005301 0.646891
+vt 0.941200 0.576589
+vt 1.034176 0.958662
+vt 0.823807 0.933258
+vt 1.003585 0.521934
+vt 0.945911 0.514786
+vt 1.015221 0.896641
+vt 0.885287 0.880701
+vt 1.002796 0.459454
+vt 0.950535 0.452971
+vt 1.010297 0.834265
+vt 0.908873 0.821779
+vt 1.001965 0.396975
+vt 0.955439 0.391196
+vt 1.007907 0.771825
+vt 0.921503 0.761167
+vt 1.001015 0.334499
+vt 0.961079 0.329532
+vt 1.006404 0.709363
+vt 0.929787 0.699898
+vt 0.968202 0.268089
+vt 0.936013 0.638321
+vt 0.488610 0.915189
+vt 0.647808 0.950687
+vt 0.921611 0.311033
+vt 0.859136 0.666985
+vt 0.937209 0.253354
+vt 0.870446 0.607941
+vt 0.532175 0.909643
+vt 0.657607 0.903302
+vt 0.959449 0.197860
+vt 0.880347 0.548455
+vt 0.745300 0.879338
+vt 0.889690 0.488794
+vt 0.796385 0.834663
+vt 0.899158 0.429173
+vt 0.825891 0.781668
+vt 0.909472 0.369816
+vt 0.845097 0.725165
+vt 0.848920 0.390841
+vt 0.761226 0.728711
+vt 0.864196 0.334814
+vt 0.780693 0.674598
+vt 0.882867 0.280332
+vt 0.796418 0.618773
+vt 0.907539 0.228698
+vt 0.810089 0.562031
+vt 0.558962 0.891763
+vt 0.641452 0.857179
+vt 0.942759 0.182515
+vt 0.822818 0.504873
+vt 0.697492 0.824480
+vt 0.835477 0.447684
+vt 0.735147 0.779653
+vt 0.879896 0.195479
+vt 0.753309 0.508011
+vt 0.618082 0.815427
+vt 0.767315 0.452094
+vt 0.657173 0.773912
+vt 0.782092 0.396562
+vt 0.685241 0.725518
+vt 0.798714 0.341964
+vt 0.706593 0.673391
+vt 0.818709 0.289116
+vt 0.723996 0.619193
+vt 0.844487 0.239416
+vt 0.739178 0.563865
+vt 0.567268 0.868303
+vt 0.563300 0.844314
+vt 0.770454 0.236269
+vt 0.670392 0.566231
+vt 0.805029 0.190637
+vt 0.683774 0.509644
+vt 0.551952 0.822879
+vt 0.929896 0.162212
+vt 0.855308 0.155368
+vt 0.697011 0.452991
+vt 0.591182 0.780044
+vt 0.710973 0.396675
+vt 0.618699 0.730484
+vt 0.726705 0.341193
+vt 0.639317 0.677374
+vt 0.745717 0.287291
+vt 0.655961 0.622327
+vt 0.665037 0.288362
+vt 0.594131 0.638967
+vt 0.684737 0.232805
+vt 0.605914 0.580518
+vt 0.713639 0.180821
+vt 0.616615 0.521685
+vt 0.760428 0.136665
+vt 0.627046 0.462757
+vt 0.536166 0.805967
+vt 0.923407 0.138703
+vt 0.836350 0.110271
+vt 0.637946 0.403995
+vt 0.562017 0.752770
+vt 0.650183 0.345708
+vt 0.580132 0.696622
+vt 0.517784 0.794886
+vt 0.927547 0.114679
+vt 0.833915 0.062714
+vt 0.573887 0.368405
+vt 0.531336 0.735069
+vt 0.581872 0.307471
+vt 0.540867 0.674443
+vt 0.592315 0.247027
+vt 0.548386 0.613417
+vt 0.607782 0.187599
+vt 0.554891 0.552189
+vt 0.635028 0.130630
+vt 0.560989 0.490881
+vt 0.696016 0.081502
+vt 0.567156 0.429587
+vt 0.502796 0.540546
+vt 0.515221 0.103359
+vt 0.503585 0.478066
+vt 0.534176 0.041338
+vt 0.504397 0.415586
+vt 0.498129 0.790428
+vt 0.948527 0.094534
+vt 0.947682 0.023355
+vt 0.505301 0.353109
+vt 0.499822 0.727971
+vt 0.506404 0.290637
+vt 0.501015 0.665501
+vt 0.507907 0.228175
+vt 0.501965 0.603025
+vt 0.510297 0.165735
+vt 0.429787 0.300102
+vt 0.461079 0.670468
+vt 0.421503 0.238833
+vt 0.455439 0.608804
+vt 0.408873 0.178221
+vt 0.445911 0.485214
+vt 0.385287 0.119299
+vt 1.323807 0.066742
+vt 0.441200 0.423411
+vt 0.478319 0.792904
+vt 0.988610 0.084811
+vt 1.147808 0.049313
+vt 0.436013 0.361679
+vt 0.468202 0.731911
+vt 0.147808 0.049313
+vt 0.323807 0.066742
+vt 0.245300 0.120661
+vt 0.380347 0.451545
+vt 0.459449 0.802140
+vt 0.032175 0.090357
+vt 0.157607 0.096698
+vt 0.370446 0.392059
+vt 0.437209 0.746646
+vt 0.359136 0.333015
+vt 0.421611 0.688967
+vt 0.345097 0.274835
+vt 0.450536 0.547029
+vt 0.409472 0.630184
+vt 0.325892 0.218332
+vt 0.399158 0.570827
+vt 0.296385 0.165337
+vt 0.389690 0.511206
+vt 0.261226 0.271289
+vt 0.348920 0.609159
+vt 0.235147 0.220347
+vt 0.335478 0.552316
+vt 0.197492 0.175520
+vt 0.322818 0.495127
+vt 0.442759 0.817485
+vt 0.058962 0.108237
+vt 0.141452 0.142821
+vt 0.310089 0.437969
+vt 0.407539 0.771302
+vt 0.296418 0.381227
+vt 0.382867 0.719668
+vt 0.280693 0.325402
+vt 0.364196 0.665186
+vt 0.223996 0.380807
+vt 0.318709 0.710884
+vt 0.206593 0.326609
+vt 0.298714 0.658036
+vt 0.185241 0.274482
+vt 0.282092 0.603438
+vt 0.157173 0.226088
+vt 0.267315 0.547906
+vt 0.118082 0.184573
+vt 0.253309 0.491989
+vt 0.379896 0.804521
+vt 0.067268 0.131697
+vt 0.063300 0.155685
+vt 0.239178 0.436135
+vt 0.344487 0.760584
+vt 0.091182 0.219955
+vt 0.197011 0.547009
+vt 0.429896 0.837788
+vt 0.355308 0.844632
+vt 0.051952 0.177121
+vt 0.183774 0.490356
+vt 0.305029 0.809363
+vt 0.170392 0.433769
+vt 0.270454 0.763731
+vt 0.155961 0.377673
+vt 0.245717 0.712709
+vt 0.226706 0.658807
+vt 0.118699 0.269516
+vt 0.210973 0.603325
+vt 0.139317 0.322626
+vt 0.094131 0.361033
+vt 0.165037 0.711638
+vt 0.080132 0.303378
+vt 0.150183 0.654292
+vt 0.062017 0.247229
+vt 0.137946 0.596005
+vt 0.423407 0.861296
+vt 0.336350 0.889729
+vt 0.036166 0.194032
+vt 0.127046 0.537243
+vt 0.260428 0.863335
+vt 0.116615 0.478315
+vt 0.213639 0.819179
+vt 0.105914 0.419482
+vt 0.184737 0.767195
+vt 0.495265 0.852856
+vt 0.995265 0.147143
+vt 1.032175 0.090357
+vt 1.058962 0.108237
+vt 1.067268 0.131697
+vt 1.063300 0.155685
+vt 1.051952 0.177121
+vt 0.427547 0.885321
+vt 1.036166 0.194032
+vt 0.031336 0.264931
+vt 0.017784 0.205113
+vn -0.563891 -0.825831 0.000000
+vn -0.713095 -0.701041 0.000000
+vn -0.520981 -0.825831 -0.215796
+vn -0.981231 0.192785 0.000000
+vn -0.925596 0.378430 0.000000
+vn -0.906522 0.192785 -0.375500
+vn -0.393017 -0.919523 0.000000
+vn -0.363109 -0.919523 -0.150395
+vn -1.000000 0.000000 0.000000
+vn -0.923856 0.000000 -0.382672
+vn -0.393017 0.919523 0.000000
+vn -0.206793 0.978362 0.000000
+vn -0.363109 0.919523 -0.150395
+vn -0.206793 -0.978362 0.000000
+vn -0.191046 -0.978362 -0.079134
+vn -0.981231 -0.192785 0.000000
+vn -0.906522 -0.192785 -0.375500
+vn -0.563891 0.825831 0.000000
+vn -0.520981 0.825831 -0.215796
+vn -0.925596 -0.378430 0.000000
+vn -0.855159 -0.378430 -0.354198
+vn -0.713095 0.701041 0.000000
+vn -0.658803 0.701041 -0.272866
+vn -0.835139 -0.550005 0.000000
+vn -0.771569 -0.550005 -0.319590
+vn -0.835139 0.550005 0.000000
+vn -0.771569 0.550005 -0.319590
+vn -0.658803 -0.701041 -0.272866
+vn -0.855159 0.378430 -0.354198
+vn -0.146214 -0.978362 -0.146214
+vn -0.693838 -0.192785 -0.693838
+vn -0.398724 0.825831 -0.398724
+vn -0.654500 -0.378430 -0.654500
+vn -0.504227 0.701041 -0.504227
+vn -0.590533 -0.550005 -0.590533
+vn -0.590533 0.550005 -0.590533
+vn -0.504227 -0.701041 -0.504227
+vn -0.654500 0.378430 -0.654500
+vn -0.398724 -0.825831 -0.398724
+vn -0.693838 0.192785 -0.693838
+vn -0.277902 -0.919523 -0.277902
+vn -0.707083 0.000000 -0.707083
+vn -0.191046 0.978362 -0.079134
+vn -0.277902 0.919523 -0.277902
+vn -0.215796 -0.825831 -0.520981
+vn -0.375500 0.192785 -0.906522
+vn -0.150395 -0.919523 -0.363109
+vn -0.382672 0.000000 -0.923856
+vn -0.146214 0.978362 -0.146214
+vn -0.150395 0.919523 -0.363109
+vn -0.079134 -0.978362 -0.191046
+vn -0.375500 -0.192785 -0.906522
+vn -0.215796 0.825831 -0.520981
+vn -0.354198 -0.378430 -0.855159
+vn -0.272866 0.701041 -0.658803
+vn -0.319590 -0.550005 -0.771569
+vn -0.319590 0.550005 -0.771569
+vn -0.272866 -0.701041 -0.658803
+vn -0.354198 0.378430 -0.855159
+vn 0.000000 -0.550005 -0.835139
+vn 0.000000 0.550005 -0.835139
+vn 0.000000 -0.701041 -0.713095
+vn 0.000000 0.378430 -0.925596
+vn 0.000000 -0.825831 -0.563891
+vn 0.000000 0.192785 -0.981231
+vn 0.000000 -0.919523 -0.393017
+vn 0.000000 0.000000 -1.000000
+vn -0.079134 0.978362 -0.191046
+vn 0.000000 0.919523 -0.393017
+vn 0.000000 -0.978362 -0.206793
+vn 0.000000 -0.192785 -0.981231
+vn 0.000000 0.825831 -0.563891
+vn 0.000000 -0.378430 -0.925596
+vn 0.000000 0.701041 -0.713095
+vn 0.150395 -0.919523 -0.363109
+vn 0.382672 0.000000 -0.923856
+vn 0.150395 0.919523 -0.363109
+vn 0.375500 -0.192785 -0.906522
+vn 0.215796 0.825831 -0.520981
+vn 0.354198 -0.378430 -0.855159
+vn 0.272866 0.701041 -0.658803
+vn 0.319590 -0.550005 -0.771569
+vn 0.319590 0.550005 -0.771569
+vn 0.272866 -0.701041 -0.658803
+vn 0.354198 0.378430 -0.855159
+vn 0.215796 -0.825831 -0.520981
+vn 0.375500 0.192785 -0.906522
+vn 0.000000 0.978362 -0.206793
+vn 0.079134 0.978362 -0.191046
+vn 0.504227 -0.701041 -0.504227
+vn 0.654500 0.378430 -0.654500
+vn 0.398724 -0.825831 -0.398724
+vn 0.693838 0.192785 -0.693838
+vn 0.146214 0.978362 -0.146214
+vn 0.079134 -0.978362 -0.191046
+vn 0.277902 -0.919523 -0.277902
+vn 0.707083 0.000000 -0.707083
+vn 0.277902 0.919523 -0.277902
+vn 0.693838 -0.192785 -0.693838
+vn 0.398724 0.825831 -0.398724
+vn 0.654500 -0.378430 -0.654500
+vn 0.504227 0.701041 -0.504227
+vn 0.590533 -0.550005 -0.590533
+vn 0.590533 0.550005 -0.590533
+vn 0.855159 -0.378430 -0.354198
+vn 0.658803 0.701041 -0.272866
+vn 0.771569 -0.550005 -0.319590
+vn 0.771569 0.550005 -0.319590
+vn 0.658803 -0.701041 -0.272866
+vn 0.855159 0.378430 -0.354198
+vn 0.520981 -0.825831 -0.215796
+vn 0.906522 0.192785 -0.375500
+vn 0.191046 0.978362 -0.079134
+vn 0.146214 -0.978362 -0.146214
+vn 0.363109 -0.919523 -0.150395
+vn 0.923856 0.000000 -0.382672
+vn 0.363109 0.919523 -0.150395
+vn 0.906522 -0.192785 -0.375500
+vn 0.520981 0.825831 -0.215796
+vn 0.206793 0.978362 0.000000
+vn 0.191046 -0.978362 -0.079134
+vn 0.393017 -0.919523 0.000000
+vn 1.000000 0.000000 0.000000
+vn 0.393017 0.919523 0.000000
+vn 0.981231 -0.192785 0.000000
+vn 0.563891 0.825831 0.000000
+vn 0.925596 -0.378430 0.000000
+vn 0.713095 0.701041 0.000000
+vn 0.835139 -0.550005 0.000000
+vn 0.835139 0.550005 0.000000
+vn 0.713095 -0.701041 0.000000
+vn 0.925596 0.378430 0.000000
+vn 0.563891 -0.825831 0.000000
+vn 0.981231 0.192785 0.000000
+vn 0.771569 0.550005 0.319590
+vn 0.658803 -0.701041 0.272866
+vn 0.855159 0.378430 0.354198
+vn 0.520981 -0.825831 0.215796
+vn 0.906522 0.192785 0.375500
+vn 0.191046 0.978362 0.079134
+vn 0.206793 -0.978362 0.000000
+vn 0.363109 -0.919523 0.150395
+vn 0.923856 0.000000 0.382672
+vn 0.363109 0.919523 0.150395
+vn 0.906522 -0.192785 0.375500
+vn 0.520981 0.825831 0.215796
+vn 0.855159 -0.378430 0.354198
+vn 0.658803 0.701041 0.272866
+vn 0.771569 -0.550005 0.319590
+vn 0.693838 -0.192785 0.693838
+vn 0.398724 0.825831 0.398724
+vn 0.654500 -0.378430 0.654500
+vn 0.504227 0.701041 0.504227
+vn 0.590533 -0.550005 0.590533
+vn 0.654500 0.378430 0.654500
+vn 0.504227 -0.701041 0.504227
+vn 0.398724 -0.825831 0.398724
+vn 0.693838 0.192785 0.693838
+vn 0.146214 0.978362 0.146214
+vn 0.191046 -0.978362 0.079134
+vn 0.277902 -0.919523 0.277902
+vn 0.707083 0.000000 0.707083
+vn 0.277902 0.919523 0.277902
+vn 0.215796 -0.825831 0.520981
+vn 0.375500 0.192785 0.906522
+vn 0.079134 0.978362 0.191046
+vn 0.146214 -0.978362 0.146214
+vn 0.150395 -0.919523 0.363109
+vn 0.382672 0.000000 0.923856
+vn 0.150395 0.919523 0.363109
+vn 0.375500 -0.192785 0.906522
+vn 0.215796 0.825831 0.520981
+vn 0.354198 -0.378430 0.855159
+vn 0.590533 0.550005 0.590533
+vn 0.272866 0.701041 0.658803
+vn 0.319590 -0.550005 0.771569
+vn 0.319590 0.550005 0.771569
+vn 0.272866 -0.701041 0.658803
+vn 0.354198 0.378430 0.855159
+vn 0.000000 -0.550005 0.835139
+vn 0.000000 0.550005 0.835139
+vn 0.000000 -0.701041 0.713095
+vn 0.000000 0.378430 0.925596
+vn 0.000000 -0.825831 0.563891
+vn 0.000000 0.192785 0.981231
+vn 0.000000 0.978362 0.206793
+vn 0.079134 -0.978362 0.191046
+vn 0.000000 -0.919523 0.393017
+vn 0.000000 0.000000 1.000000
+vn 0.000000 0.919523 0.393017
+vn 0.000000 -0.192785 0.981231
+vn 0.000000 0.825831 0.563891
+vn 0.000000 -0.378430 0.925596
+vn 0.000000 0.701041 0.713095
+vn -0.354198 -0.378430 0.855159
+vn -0.272866 0.701041 0.658803
+vn -0.319590 -0.550005 0.771569
+vn -0.319590 0.550005 0.771569
+vn -0.272866 -0.701041 0.658803
+vn -0.354198 0.378430 0.855159
+vn -0.215796 -0.825831 0.520981
+vn -0.375500 0.192785 0.906522
+vn -0.150395 -0.919523 0.363109
+vn -0.382672 0.000000 0.923856
+vn -0.150395 0.919523 0.363109
+vn 0.000000 -0.978362 0.206793
+vn -0.079134 -0.978362 0.191046
+vn -0.375500 -0.192785 0.906522
+vn -0.215796 0.825831 0.520981
+vn -0.277902 -0.919523 0.277902
+vn -0.707083 0.000000 0.707083
+vn -0.079134 0.978362 0.191046
+vn -0.277902 0.919523 0.277902
+vn -0.146214 -0.978362 0.146214
+vn -0.693838 -0.192785 0.693838
+vn -0.398724 0.825831 0.398724
+vn -0.654500 -0.378430 0.654500
+vn -0.504227 0.701041 0.504227
+vn -0.590533 -0.550005 0.590533
+vn -0.590533 0.550005 0.590533
+vn -0.654500 0.378430 0.654500
+vn -0.398724 -0.825831 0.398724
+vn -0.693838 0.192785 0.693838
+vn -0.504227 -0.701041 0.504227
+vn -0.658803 -0.701041 0.272866
+vn -0.855159 0.378430 0.354198
+vn -0.520981 -0.825831 0.215796
+vn -0.906522 0.192785 0.375500
+vn -0.363109 -0.919523 0.150395
+vn -0.923856 0.000000 0.382672
+vn -0.146214 0.978362 0.146214
+vn -0.363109 0.919523 0.150395
+vn -0.191046 -0.978362 0.079134
+vn -0.906522 -0.192785 0.375500
+vn -0.520981 0.825831 0.215796
+vn -0.855159 -0.378430 0.354198
+vn -0.658803 0.701041 0.272866
+vn -0.771569 -0.550005 0.319590
+vn -0.771569 0.550005 0.319590
+vn 0.000000 0.999969 0.000000
+vn 0.000000 -1.000000 0.000000
+vn -0.191046 0.978362 0.079134
+s 1
+f 13/1/1 12/2/2 28/3/3
+f 7/4/4 6/5/5 22/6/6
+f 14/7/7 13/8/1 29/9/8
+f 8/10/9 7/4/4 23/11/10
+f 2/12/11 1/13/12 17/14/13
+f 15/15/14 14/7/7 30/16/15
+f 9/17/16 8/10/9 24/18/17
+f 3/19/18 2/12/11 18/20/19
+f 10/21/20 9/17/16 25/22/21
+f 4/23/22 3/19/18 19/24/23
+f 11/25/24 10/21/20 26/26/25
+f 5/27/26 4/23/22 20/28/27
+f 12/2/2 11/25/24 27/29/28
+f 6/5/5 5/27/26 21/30/29
+f 30/16/15 29/9/8 46/31/30
+f 24/32/17 23/33/10 40/34/31
+f 18/35/19 17/14/13 34/36/32
+f 25/37/21 24/32/17 41/38/33
+f 19/39/23 18/35/19 35/40/34
+f 26/41/25 25/37/21 42/42/35
+f 20/43/27 19/39/23 36/44/36
+f 27/45/28 26/41/25 43/46/37
+f 21/47/29 20/43/27 37/48/38
+f 28/49/3 27/45/28 44/50/39
+f 22/51/6 21/47/29 38/52/40
+f 29/9/8 28/49/3 45/53/41
+f 23/33/10 22/51/6 39/54/42
+f 17/14/13 16/55/43 33/56/44
+f 44/50/39 43/46/37 59/57/45
+f 38/52/40 37/48/38 53/58/46
+f 45/53/41 44/50/39 60/59/47
+f 39/54/42 38/52/40 54/60/48
+f 33/56/44 32/61/49 48/62/50
+f 46/31/30 45/53/41 61/63/51
+f 40/34/31 39/54/42 55/64/52
+f 34/36/32 33/56/44 49/65/53
+f 41/38/33 40/34/31 56/66/54
+f 35/40/34 34/36/32 50/67/55
+f 42/42/35 41/38/33 57/68/56
+f 36/44/36 35/40/34 51/69/57
+f 43/46/37 42/42/35 58/70/58
+f 37/48/38 36/44/36 52/71/59
+f 57/68/56 56/66/54 72/72/60
+f 51/69/57 50/67/55 66/73/61
+f 58/70/58 57/68/56 73/74/62
+f 52/71/59 51/69/57 67/75/63
+f 59/57/45 58/70/58 74/76/64
+f 53/58/46 52/71/59 68/77/65
+f 60/59/47 59/57/45 75/78/66
+f 54/60/48 53/58/46 69/79/67
+f 48/62/50 47/80/68 63/81/69
+f 61/63/51 60/59/47 76/82/70
+f 55/64/52 54/60/48 70/83/71
+f 49/65/53 48/62/50 64/84/72
+f 56/66/54 55/64/52 71/85/73
+f 50/67/55 49/65/53 65/86/74
+f 76/82/70 75/78/66 90/87/75
+f 70/83/71 69/79/67 84/88/76
+f 64/84/72 63/81/69 78/89/77
+f 71/85/73 70/83/71 85/90/78
+f 65/86/74 64/84/72 79/91/79
+f 72/72/60 71/85/73 86/92/80
+f 66/73/61 65/86/74 80/93/81
+f 73/74/62 72/72/60 87/94/82
+f 67/75/63 66/73/61 81/95/83
+f 74/76/64 73/74/62 88/96/84
+f 68/77/65 67/75/63 82/97/85
+f 75/78/66 74/76/64 89/98/86
+f 69/79/67 68/77/65 83/99/87
+f 63/81/69 62/100/88 77/101/89
+f 89/98/86 88/96/84 103/102/90
+f 83/99/87 82/97/85 97/103/91
+f 90/87/75 89/98/86 104/104/92
+f 84/88/76 83/99/87 98/105/93
+f 78/89/77 77/101/89 92/106/94
+f 91/107/95 90/87/75 105/108/96
+f 85/90/78 84/88/76 99/109/97
+f 79/91/79 78/89/77 93/110/98
+f 86/92/80 85/90/78 100/111/99
+f 80/93/81 79/91/79 94/112/100
+f 87/94/82 86/92/80 101/113/101
+f 81/95/83 80/93/81 95/114/102
+f 88/96/84 87/94/82 102/115/103
+f 82/97/85 81/95/83 96/116/104
+f 102/115/103 101/113/101 116/117/105
+f 96/116/104 95/114/102 110/118/106
+f 103/102/90 102/115/103 117/119/107
+f 97/103/91 96/116/104 111/120/108
+f 104/104/92 103/102/90 118/121/109
+f 98/105/93 97/103/91 112/122/110
+f 105/108/96 104/104/92 119/123/111
+f 99/109/97 98/105/93 113/124/112
+f 93/110/98 92/106/94 107/125/113
+f 106/126/114 105/108/96 120/127/115
+f 100/111/99 99/109/97 114/128/116
+f 94/112/100 93/110/98 108/129/117
+f 101/113/101 100/111/99 115/130/118
+f 95/114/102 94/112/100 109/131/119
+f 108/129/117 107/125/113 122/132/120
+f 121/133/121 120/127/115 135/134/122
+f 115/130/118 114/128/116 129/135/123
+f 109/131/119 108/129/117 123/136/124
+f 116/117/105 115/130/118 130/137/125
+f 110/118/106 109/131/119 124/138/126
+f 117/119/107 116/117/105 131/139/127
+f 111/120/108 110/118/106 125/140/128
+f 118/121/109 117/119/107 132/141/129
+f 112/122/110 111/120/108 126/142/130
+f 119/123/111 118/121/109 133/143/131
+f 113/124/112 112/122/110 127/144/132
+f 120/127/115 119/123/111 134/145/133
+f 114/128/116 113/124/112 128/146/134
+f 127/144/132 126/142/130 141/147/135
+f 134/145/133 133/143/131 148/148/136
+f 128/146/134 127/144/132 142/149/137
+f 135/134/122 134/145/133 149/150/138
+f 129/135/123 128/146/134 143/151/139
+f 123/136/124 122/132/120 137/152/140
+f 136/153/141 135/134/122 150/154/142
+f 130/137/125 129/135/123 144/155/143
+f 124/138/126 123/136/124 138/156/144
+f 131/139/127 130/137/125 145/157/145
+f 125/140/128 124/138/126 139/158/146
+f 132/141/129 131/139/127 146/159/147
+f 126/142/130 125/140/128 140/160/148
+f 133/143/131 132/141/129 147/161/149
+f 146/159/147 145/157/145 160/162/150
+f 140/160/148 139/158/146 154/163/151
+f 147/161/149 146/159/147 161/164/152
+f 141/147/135 140/160/148 155/165/153
+f 148/148/136 147/161/149 162/166/154
+f 142/149/137 141/147/135 157/167/155
+f 149/150/138 148/148/136 163/168/156
+f 143/151/139 142/149/137 157/167/155
+f 150/154/142 149/150/138 164/169/157
+f 144/155/143 143/151/139 158/170/158
+f 138/156/144 137/152/140 152/171/159
+f 151/172/160 150/154/142 165/173/161
+f 145/157/145 144/155/143 159/174/162
+f 139/158/146 138/156/144 153/175/163
+f 165/176/161 164/177/157 179/178/164
+f 159/174/162 158/170/158 173/179/165
+f 153/175/163 152/171/159 167/180/166
+f 166/181/167 165/176/161 180/182/168
+f 160/162/150 159/174/162 174/183/169
+f 154/163/151 153/175/163 168/184/170
+f 161/164/152 160/162/150 175/185/171
+f 155/165/153 154/163/151 169/186/172
+f 162/166/154 161/164/152 176/187/173
+f 156/188/174 155/165/153 170/189/175
+f 163/168/156 162/166/154 177/190/176
+f 157/167/155 156/188/174 171/191/177
+f 164/177/157 163/168/156 178/192/178
+f 158/170/158 157/167/155 172/193/179
+f 178/192/178 177/190/176 192/194/180
+f 172/193/179 171/191/177 186/195/181
+f 179/178/164 178/192/178 193/196/182
+f 173/179/165 172/193/179 187/197/183
+f 180/182/168 179/178/164 194/198/184
+f 174/183/169 173/179/165 188/199/185
+f 168/184/170 167/180/166 182/200/186
+f 181/201/187 180/182/168 195/202/188
+f 175/185/171 174/183/169 189/203/189
+f 169/186/172 168/184/170 183/204/190
+f 176/187/173 175/185/171 190/205/191
+f 170/189/175 169/186/172 184/206/192
+f 177/190/176 176/187/173 191/207/193
+f 171/191/177 170/189/175 185/208/194
+f 191/207/193 190/205/191 206/209/195
+f 185/208/194 184/206/192 200/210/196
+f 192/194/180 191/207/193 207/211/197
+f 186/195/181 185/208/194 201/212/198
+f 193/196/182 192/194/180 208/213/199
+f 187/197/183 186/195/181 202/214/200
+f 194/198/184 193/196/182 209/215/201
+f 188/199/185 187/197/183 203/216/202
+f 195/202/188 194/198/184 210/217/203
+f 189/203/189 188/199/185 204/218/204
+f 183/204/190 182/200/186 198/219/205
+f 196/220/206 195/202/188 211/221/207
+f 190/205/191 189/203/189 205/222/208
+f 184/206/192 183/204/190 199/223/209
+f 210/217/203 209/215/201 226/224/210
+f 204/218/204 203/216/202 220/225/211
+f 198/219/205 197/226/212 214/227/213
+f 211/221/207 210/217/203 227/228/214
+f 205/222/208 204/218/204 221/229/215
+f 199/223/209 198/219/205 215/230/216
+f 206/209/195 205/222/208 222/231/217
+f 200/210/196 199/223/209 216/232/218
+f 207/211/197 206/209/195 223/233/219
+f 201/212/198 200/210/196 217/234/220
+f 208/213/199 207/211/197 223/233/219
+f 202/214/200 201/212/198 218/235/221
+f 209/215/201 208/213/199 225/236/222
+f 203/216/202 202/214/200 219/237/223
+f 224/238/224 223/233/219 239/239/225
+f 218/235/221 217/234/220 233/240/226
+f 225/236/222 224/238/224 240/241/227
+f 219/237/223 218/235/221 234/242/228
+f 226/224/210 225/236/222 241/243/229
+f 220/225/211 219/237/223 235/244/230
+f 214/227/213 213/245/231 229/246/232
+f 227/228/214 226/224/210 242/247/233
+f 221/229/215 220/225/211 236/248/234
+f 215/230/216 214/227/213 230/249/235
+f 222/231/217 221/229/215 237/250/236
+f 216/232/218 215/230/216 231/251/237
+f 223/233/219 222/231/217 238/252/238
+f 217/234/220 216/232/218 232/253/239
+f 1/13/12 212/254/240 16/55/43
+f 31/255/241 15/15/14 30/16/15
+f 31/255/241 30/16/15 46/31/30
+f 16/55/43 212/254/240 32/61/49
+f 32/61/49 212/254/240 47/80/68
+f 31/255/241 46/31/30 61/63/51
+f 47/80/68 212/254/240 62/100/88
+f 31/255/241 61/63/51 76/82/70
+f 31/255/241 76/82/70 91/107/95
+f 62/100/88 212/254/240 77/101/89
+f 77/101/89 212/254/240 92/106/94
+f 31/255/241 91/107/95 106/126/114
+f 92/106/94 212/254/240 107/125/113
+f 31/255/241 106/126/114 121/133/121
+f 31/255/241 121/133/121 136/153/141
+f 107/125/113 212/254/240 122/132/120
+f 122/132/120 212/254/240 137/152/140
+f 31/255/241 136/153/141 151/172/160
+f 137/152/140 212/254/240 152/171/159
+f 31/255/241 151/172/160 166/256/167
+f 31/255/241 166/256/167 181/257/187
+f 152/171/159 212/254/240 167/180/166
+f 167/180/166 212/254/240 182/200/186
+f 31/255/241 181/257/187 196/258/206
+f 31/255/241 196/258/206 211/259/207
+f 182/200/186 212/254/240 197/226/212
+f 31/255/241 211/259/207 227/260/214
+f 197/226/212 212/254/240 213/245/231
+f 213/245/231 212/254/240 228/261/242
+f 31/255/241 227/260/214 242/262/233
+f 31/255/241 242/262/233 15/15/14
+f 237/250/236 236/248/234 10/21/20
+f 231/251/237 230/249/235 4/23/22
+f 238/252/238 237/250/236 10/21/20
+f 232/253/239 231/251/237 5/27/26
+f 239/239/225 238/252/238 11/25/24
+f 233/240/226 232/253/239 6/5/5
+f 240/241/227 239/239/225 13/1/1
+f 234/242/228 233/240/226 7/4/4
+f 228/261/242 212/254/240 1/13/12
+f 241/243/229 240/241/227 14/263/7
+f 235/244/230 234/242/228 8/10/9
+f 229/246/232 228/261/242 2/12/11
+f 242/247/233 241/243/229 15/264/14
+f 236/248/234 235/244/230 9/17/16
+f 230/249/235 229/246/232 3/19/18
+f 12/2/2 27/29/28 28/3/3
+f 6/5/5 21/30/29 22/6/6
+f 13/8/1 28/49/3 29/9/8
+f 7/4/4 22/6/6 23/11/10
+f 1/13/12 16/55/43 17/14/13
+f 14/7/7 29/9/8 30/16/15
+f 8/10/9 23/11/10 24/18/17
+f 2/12/11 17/14/13 18/20/19
+f 9/17/16 24/18/17 25/22/21
+f 3/19/18 18/20/19 19/24/23
+f 10/21/20 25/22/21 26/26/25
+f 4/23/22 19/24/23 20/28/27
+f 11/25/24 26/26/25 27/29/28
+f 5/27/26 20/28/27 21/30/29
+f 29/9/8 45/53/41 46/31/30
+f 23/33/10 39/54/42 40/34/31
+f 17/14/13 33/56/44 34/36/32
+f 24/32/17 40/34/31 41/38/33
+f 18/35/19 34/36/32 35/40/34
+f 25/37/21 41/38/33 42/42/35
+f 19/39/23 35/40/34 36/44/36
+f 26/41/25 42/42/35 43/46/37
+f 20/43/27 36/44/36 37/48/38
+f 27/45/28 43/46/37 44/50/39
+f 21/47/29 37/48/38 38/52/40
+f 28/49/3 44/50/39 45/53/41
+f 22/51/6 38/52/40 39/54/42
+f 16/55/43 32/61/49 33/56/44
+f 43/46/37 58/70/58 59/57/45
+f 37/48/38 52/71/59 53/58/46
+f 44/50/39 59/57/45 60/59/47
+f 38/52/40 53/58/46 54/60/48
+f 32/61/49 47/80/68 48/62/50
+f 45/53/41 60/59/47 61/63/51
+f 39/54/42 54/60/48 55/64/52
+f 33/56/44 48/62/50 49/65/53
+f 40/34/31 55/64/52 56/66/54
+f 34/36/32 49/65/53 50/67/55
+f 41/38/33 56/66/54 57/68/56
+f 35/40/34 50/67/55 51/69/57
+f 42/42/35 57/68/56 58/70/58
+f 36/44/36 51/69/57 52/71/59
+f 56/66/54 71/85/73 72/72/60
+f 50/67/55 65/86/74 66/73/61
+f 57/68/56 72/72/60 73/74/62
+f 51/69/57 66/73/61 67/75/63
+f 58/70/58 73/74/62 74/76/64
+f 52/71/59 67/75/63 68/77/65
+f 59/57/45 74/76/64 75/78/66
+f 53/58/46 68/77/65 69/79/67
+f 47/80/68 62/100/88 63/81/69
+f 60/59/47 75/78/66 76/82/70
+f 54/60/48 69/79/67 70/83/71
+f 48/62/50 63/81/69 64/84/72
+f 55/64/52 70/83/71 71/85/73
+f 49/65/53 64/84/72 65/86/74
+f 91/107/95 76/82/70 90/87/75
+f 85/90/78 70/83/71 84/88/76
+f 79/91/79 64/84/72 78/89/77
+f 86/92/80 71/85/73 85/90/78
+f 80/93/81 65/86/74 79/91/79
+f 87/94/82 72/72/60 86/92/80
+f 81/95/83 66/73/61 80/93/81
+f 88/96/84 73/74/62 87/94/82
+f 82/97/85 67/75/63 81/95/83
+f 89/98/86 74/76/64 88/96/84
+f 83/99/87 68/77/65 82/97/85
+f 90/87/75 75/78/66 89/98/86
+f 84/88/76 69/79/67 83/99/87
+f 78/89/77 63/81/69 77/101/89
+f 104/104/92 89/98/86 103/102/90
+f 98/105/93 83/99/87 97/103/91
+f 105/108/96 90/87/75 104/104/92
+f 99/109/97 84/88/76 98/105/93
+f 93/110/98 78/89/77 92/106/94
+f 106/126/114 91/107/95 105/108/96
+f 100/111/99 85/90/78 99/109/97
+f 94/112/100 79/91/79 93/110/98
+f 101/113/101 86/92/80 100/111/99
+f 95/114/102 80/93/81 94/112/100
+f 102/115/103 87/94/82 101/113/101
+f 96/116/104 81/95/83 95/114/102
+f 103/102/90 88/96/84 102/115/103
+f 97/103/91 82/97/85 96/116/104
+f 117/119/107 102/115/103 116/117/105
+f 111/120/108 96/116/104 110/118/106
+f 118/121/109 103/102/90 117/119/107
+f 112/122/110 97/103/91 111/120/108
+f 119/123/111 104/104/92 118/121/109
+f 113/124/112 98/105/93 112/122/110
+f 120/127/115 105/108/96 119/123/111
+f 114/128/116 99/109/97 113/124/112
+f 108/129/117 93/110/98 107/125/113
+f 121/133/121 106/126/114 120/127/115
+f 115/130/118 100/111/99 114/128/116
+f 109/131/119 94/112/100 108/129/117
+f 116/117/105 101/113/101 115/130/118
+f 110/118/106 95/114/102 109/131/119
+f 123/136/124 108/129/117 122/132/120
+f 136/153/141 121/133/121 135/134/122
+f 130/137/125 115/130/118 129/135/123
+f 124/138/126 109/131/119 123/136/124
+f 131/139/127 116/117/105 130/137/125
+f 125/140/128 110/118/106 124/138/126
+f 132/141/129 117/119/107 131/139/127
+f 126/142/130 111/120/108 125/140/128
+f 133/143/131 118/121/109 132/141/129
+f 127/144/132 112/122/110 126/142/130
+f 134/145/133 119/123/111 133/143/131
+f 128/146/134 113/124/112 127/144/132
+f 135/134/122 120/127/115 134/145/133
+f 129/135/123 114/128/116 128/146/134
+f 142/149/137 127/144/132 141/147/135
+f 149/150/138 134/145/133 148/148/136
+f 143/151/139 128/146/134 142/149/137
+f 150/154/142 135/134/122 149/150/138
+f 144/155/143 129/135/123 143/151/139
+f 138/156/144 123/136/124 137/152/140
+f 151/172/160 136/153/141 150/154/142
+f 145/157/145 130/137/125 144/155/143
+f 139/158/146 124/138/126 138/156/144
+f 146/159/147 131/139/127 145/157/145
+f 140/160/148 125/140/128 139/158/146
+f 147/161/149 132/141/129 146/159/147
+f 141/147/135 126/142/130 140/160/148
+f 148/148/136 133/143/131 147/161/149
+f 161/164/152 146/159/147 160/162/150
+f 155/165/153 140/160/148 154/163/151
+f 162/166/154 147/161/149 161/164/152
+f 156/188/174 141/147/135 155/165/153
+f 163/168/156 148/148/136 162/166/154
+f 141/147/135 156/188/174 157/167/155
+f 164/177/157 149/150/138 163/168/156
+f 158/170/158 143/151/139 157/167/155
+f 165/173/161 150/154/142 164/169/157
+f 159/174/162 144/155/143 158/170/158
+f 153/175/163 138/156/144 152/171/159
+f 166/256/167 151/172/160 165/173/161
+f 160/162/150 145/157/145 159/174/162
+f 154/163/151 139/158/146 153/175/163
+f 180/182/168 165/176/161 179/178/164
+f 174/183/169 159/174/162 173/179/165
+f 168/184/170 153/175/163 167/180/166
+f 181/201/187 166/181/167 180/182/168
+f 175/185/171 160/162/150 174/183/169
+f 169/186/172 154/163/151 168/184/170
+f 176/187/173 161/164/152 175/185/171
+f 170/189/175 155/165/153 169/186/172
+f 177/190/176 162/166/154 176/187/173
+f 171/191/177 156/188/174 170/189/175
+f 178/192/178 163/168/156 177/190/176
+f 172/193/179 157/167/155 171/191/177
+f 179/178/164 164/177/157 178/192/178
+f 173/179/165 158/170/158 172/193/179
+f 193/196/182 178/192/178 192/194/180
+f 187/197/183 172/193/179 186/195/181
+f 194/198/184 179/178/164 193/196/182
+f 188/199/185 173/179/165 187/197/183
+f 195/202/188 180/182/168 194/198/184
+f 189/203/189 174/183/169 188/199/185
+f 183/204/190 168/184/170 182/200/186
+f 196/220/206 181/201/187 195/202/188
+f 190/205/191 175/185/171 189/203/189
+f 184/206/192 169/186/172 183/204/190
+f 191/207/193 176/187/173 190/205/191
+f 185/208/194 170/189/175 184/206/192
+f 192/194/180 177/190/176 191/207/193
+f 186/195/181 171/191/177 185/208/194
+f 190/205/191 205/222/208 206/209/195
+f 184/206/192 199/223/209 200/210/196
+f 191/207/193 206/209/195 207/211/197
+f 185/208/194 200/210/196 201/212/198
+f 192/194/180 207/211/197 208/213/199
+f 186/195/181 201/212/198 202/214/200
+f 193/196/182 208/213/199 209/215/201
+f 187/197/183 202/214/200 203/216/202
+f 194/198/184 209/215/201 210/217/203
+f 188/199/185 203/216/202 204/218/204
+f 182/200/186 197/226/212 198/219/205
+f 195/202/188 210/217/203 211/221/207
+f 189/203/189 204/218/204 205/222/208
+f 183/204/190 198/219/205 199/223/209
+f 209/215/201 225/236/222 226/224/210
+f 203/216/202 219/237/223 220/225/211
+f 197/226/212 213/245/231 214/227/213
+f 210/217/203 226/224/210 227/228/214
+f 204/218/204 220/225/211 221/229/215
+f 198/219/205 214/227/213 215/230/216
+f 205/222/208 221/229/215 222/231/217
+f 199/223/209 215/230/216 216/232/218
+f 206/209/195 222/231/217 223/233/219
+f 200/210/196 216/232/218 217/234/220
+f 224/238/224 208/213/199 223/233/219
+f 201/212/198 217/234/220 218/235/221
+f 208/213/199 224/238/224 225/236/222
+f 202/214/200 218/235/221 219/237/223
+f 223/233/219 238/252/238 239/239/225
+f 217/234/220 232/253/239 233/240/226
+f 224/238/224 239/239/225 240/241/227
+f 218/235/221 233/240/226 234/242/228
+f 225/236/222 240/241/227 241/243/229
+f 219/237/223 234/242/228 235/244/230
+f 213/245/231 228/261/242 229/246/232
+f 226/224/210 241/243/229 242/247/233
+f 220/225/211 235/244/230 236/248/234
+f 214/227/213 229/246/232 230/249/235
+f 221/229/215 236/248/234 237/250/236
+f 215/230/216 230/249/235 231/251/237
+f 222/231/217 237/250/236 238/252/238
+f 216/232/218 231/251/237 232/253/239
+f 236/248/234 9/17/16 10/21/20
+f 230/249/235 3/19/18 4/23/22
+f 11/25/24 238/252/238 10/21/20
+f 231/251/237 4/23/22 5/27/26
+f 12/2/2 239/239/225 11/25/24
+f 232/253/239 5/27/26 6/5/5
+f 239/239/225 12/2/2 13/1/1
+f 233/240/226 6/5/5 7/4/4
+f 240/241/227 13/1/1 14/263/7
+f 234/242/228 7/4/4 8/10/9
+f 228/261/242 1/13/12 2/12/11
+f 241/243/229 14/263/7 15/264/14
+f 235/244/230 8/10/9 9/17/16
+f 229/246/232 2/12/11 3/19/18
diff --git a/src/datavis3d/engine/q3dbars.cpp b/src/datavis3d/engine/q3dbars.cpp
new file mode 100644
index 00000000..c991cd4b
--- /dev/null
+++ b/src/datavis3d/engine/q3dbars.cpp
@@ -0,0 +1,2105 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dbars.h"
+#include "q3dbars_p.h"
+#include "camerahelper_p.h"
+#include "qdataitem_p.h"
+#include "qdatarow_p.h"
+#include "qdataset_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "texturehelper_p.h"
+#include "theme_p.h"
+#include "utils_p.h"
+#include "drawer_p.h"
+
+#include <QMatrix4x4>
+#include <QOpenGLPaintDevice>
+#include <QPainter>
+#include <QScreen>
+#include <QMouseEvent>
+
+#include <qmath.h>
+
+#include <QDebug>
+
+// Uncommenting this draws the shadow map with wider FOV than scene itself, making the light
+// seem to be closer to scene than it actually is. This way shadows look slightly better (to me anyway)
+#define USE_WIDER_SHADOWS
+
+// You can verify that depth buffer drawing works correctly by uncommenting this.
+// You should see the scene from where the light is
+//#define SHOW_DEPTH_TEXTURE_SCENE
+
+//#define DISPLAY_RENDER_SPEED
+
+#ifdef DISPLAY_RENDER_SPEED
+#include <QTime>
+#endif
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+//#define USE_HAX0R_SELECTION // keep this defined until the "real" method works
+#define DISPLAY_FULL_DATA_ON_SELECTION // Append selection value text with row and column labels
+
+const GLfloat gridLineWidth = 0.005f;
+
+Q3DBars::Q3DBars()
+ : d_ptr(new Q3DBarsPrivate(this))
+{
+}
+
+Q3DBars::~Q3DBars()
+{
+}
+
+void Q3DBars::initialize()
+{
+ // Initialize shaders
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ // Init the depth buffer (for shadows)
+ d_ptr->initDepthBuffer();
+ } else {
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragmentColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+ d_ptr->initLabelShaders(QStringLiteral(":/shaders/vertexLabel"),
+ QStringLiteral(":/shaders/fragmentLabel"));
+
+ // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api.
+ d_ptr->initDepthShader();
+
+ // Init selection shader
+ d_ptr->initSelectionShader();
+
+#ifndef USE_HAX0R_SELECTION
+ // Init the selection buffer
+ d_ptr->initSelectionBuffer();
+#endif
+
+ // Load default mesh
+ d_ptr->loadBarMesh();
+
+ // Load background mesh
+ d_ptr->loadBackgroundMesh();
+
+ // Load grid line mesh
+ d_ptr->loadGridLineMesh();
+
+ // Load label mesh
+ d_ptr->loadLabelMesh();
+
+ // Set OpenGL features
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+
+ // Set initial camera position
+ // X must be 0 for rotation to work - we can use "setCameraRotation" for setting it later
+ CameraHelper::setDefaultCameraOrientation(QVector3D(0.0f, 0.0f, 6.0f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+
+ // Set view port
+ glViewport(0, 0, width(), height());
+
+ // Set initialized -flag
+ d_ptr->m_isInitialized = true;
+}
+
+void Q3DBars::render()
+{
+ if (!d_ptr->m_isInitialized)
+ return;
+
+#ifdef DISPLAY_RENDER_SPEED
+ // For speed computation
+ static bool firstRender = true;
+ static QTime lastTime;
+ static GLint nbFrames = 0;
+ if (firstRender) {
+ lastTime.start();
+ firstRender = false;
+ }
+
+ // Measure speed (as milliseconds per frame)
+ nbFrames++;
+ if (lastTime.elapsed() >= 1000) { // print only if last measurement was more than 1s ago
+ qDebug() << qreal(lastTime.elapsed()) / qreal(nbFrames) << "ms/frame (=" << qreal(nbFrames) << "fps)";
+ nbFrames = 0;
+ lastTime.restart();
+ }
+#endif
+
+ // If zoom selection is on, draw zoom scene
+ drawZoomScene();
+ // Draw bars scene
+ drawScene();
+}
+
+void Q3DBars::drawZoomScene()
+{
+ // Set clear color
+ QVector3D clearColor = Utils::vectorFromColor(d_ptr->m_theme->m_windowColor);
+ glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ // If no zoom, return
+ if (!d_ptr->m_zoomActivated)
+ return;
+
+ GLfloat barPosX = 0;
+ GLint startBar = 0;
+ GLint stopBar = d_ptr->m_zoomSelection->d_ptr->row().size();
+ GLint stepBar = 1;
+ QVector3D lightPos;
+
+ // Specify viewport
+ glViewport(d_ptr->m_zoomViewPort.x(), d_ptr->m_zoomViewPort.y(),
+ d_ptr->m_zoomViewPort.width(), d_ptr->m_zoomViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+ projectionMatrix.perspective(45.0f, (GLfloat)d_ptr->m_zoomViewPort.width()
+ / (GLfloat)d_ptr->m_zoomViewPort.height(), 0.1f, 100.0f);
+
+#ifdef ROTATE_ZOOM_SELECTION
+ // Calculate view matrix
+ QMatrix4x4 viewMatrix = CameraHelper::calculateViewMatrix(d_ptr->m_mousePos,
+ d_ptr->m_zoomLevel
+ * d_ptr->m_zoomAdjustment,
+ d_ptr->m_zoomViewPort.width(),
+ d_ptr->m_zoomViewPort.height());
+
+ // Get light position (rotate light with camera, a bit above it (as set in defaultLightPos))
+ lightPos = CameraHelper::calculateLightPosition(defaultLightPos);
+
+ if (viewMatrix.row(0).z() <= 0) {
+ startBar = d_ptr->m_zoomSelection->d_ptr->row().size() - 1;
+ stopBar = -1;
+ stepBar = -1;
+ }
+#else
+ // Set view matrix
+ QMatrix4x4 viewMatrix;
+
+ viewMatrix.lookAt(QVector3D(0.0f, 0.0f, 5.0f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+
+ // Adjust scaling (zoom rate based on aspect ratio)
+ viewMatrix.scale(d_ptr->m_zoomAdjustment);
+
+ // Set light position a bit above the camera (depends on do we have row or column zoom)
+ if (ModeZoomColumn == d_ptr->m_selectionMode)
+ lightPos = CameraHelper::calculateLightPosition(defaultLightPos, -85.0f);
+ else
+ lightPos = CameraHelper::calculateLightPosition(defaultLightPos, 5.0f);
+#endif
+
+ // Bind bar shader
+ d_ptr->m_barShader->bind();
+
+ // Draw bars
+ // Draw the selected row / column
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(bar);
+ if (!item)
+ continue;
+
+ GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer;
+
+ if (barHeight < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ GLfloat barPosY = item->d_ptr->translation().y() - d_ptr->m_yAdjustment / 2.0f + 0.2f; // we need some room for labels underneath; add +0.2f
+ if (ModeZoomRow == d_ptr->m_selectionMode)
+ barPosX = item->d_ptr->translation().x();
+ else
+ barPosX = -(item->d_ptr->translation().z() - zComp); // flip z; frontmost bar to the left
+ modelMatrix.translate(barPosX, barPosY, zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ));
+ itModelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+
+ QVector3D baseColor = Utils::vectorFromColor(d_ptr->m_theme->m_baseColor);
+ QVector3D heightColor = Utils::vectorFromColor(d_ptr->m_theme->m_heightColor) * barHeight;
+
+ QVector3D barColor = baseColor + heightColor;
+
+ GLfloat lightStrength = d_ptr->m_theme->m_lightStrength;
+
+ if (barHeight != 0) {
+ // Set shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightP(), lightPos);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->view(), viewMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->color(), barColor);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), lightStrength);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->ambientS(),
+ d_ptr->m_theme->m_ambientStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj);
+ }
+ }
+
+ // Release bar shader
+ d_ptr->m_barShader->release();
+
+ // Draw labels
+ d_ptr->m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ glCullFace(GL_BACK);
+ if (d_ptr->m_labelTransparency > TransparencyNone) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ // Draw labels for axes
+ QDataItem *dummyItem = NULL;
+ LabelItem x;
+ LabelItem z;
+ LabelItem y;
+ d_ptr->m_dataSet->d_ptr->axisLabelItems(&x, &z, &y);
+ LabelItem zoomSelectionLabel = d_ptr->m_zoomSelection->d_ptr->labelItem();
+ if (ModeZoomRow == d_ptr->m_selectionMode) {
+ d_ptr->m_drawer->drawLabel(*dummyItem, zoomSelectionLabel, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, false, false, LabelTop);
+ d_ptr->m_drawer->drawLabel(*dummyItem, z, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, false, false, LabelBottom);
+ } else {
+ d_ptr->m_drawer->drawLabel(*dummyItem, x, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, false, false, LabelBottom);
+ d_ptr->m_drawer->drawLabel(*dummyItem, zoomSelectionLabel, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, false, false, LabelTop);
+ }
+ d_ptr->m_drawer->drawLabel(*dummyItem, y, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 90.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, false, false, LabelLeft);
+
+ // Draw labels for bars
+ for (int col = 0; col < d_ptr->m_zoomSelection->d_ptr->row().size(); col++) {
+ QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(col);
+ // Draw values
+ d_ptr->m_drawer->drawLabel(*item, item->d_ptr->label(), viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj);
+ // Draw labels
+ LabelItem labelItem;
+ if (ModeZoomRow == d_ptr->m_selectionMode) {
+ if (d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > col) {
+ // If draw order of bars is flipped, label draw order should be too
+ if (d_ptr->m_xFlipped) {
+ labelItem = d_ptr->m_dataSet->d_ptr->columnLabelItems().at(
+ d_ptr->m_dataSet->d_ptr->columnLabelItems().size() - col - 1);
+ } else {
+ labelItem = d_ptr->m_dataSet->d_ptr->columnLabelItems().at(col);
+ }
+ }
+ } else {
+ if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > col) {
+ // If draw order of bars is flipped, label draw order should be too
+ if (d_ptr->m_zFlipped) {
+ labelItem = d_ptr->m_dataSet->d_ptr->rowLabelItems().at(
+ d_ptr->m_dataSet->d_ptr->rowLabelItems().size() - col - 1);
+ } else {
+ labelItem = d_ptr->m_dataSet->d_ptr->rowLabelItems().at(col);
+ }
+ }
+ }
+ d_ptr->m_drawer->drawLabel(*item, labelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, -45.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, false, false, LabelBelow);
+ }
+
+ glDisable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone)
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+
+ // Release label shader
+ d_ptr->m_labelShader->release();
+}
+
+void Q3DBars::drawScene()
+{
+ GLint startBar = 0;
+ GLint stopBar = 0;
+ GLint stepBar = 0;
+
+ GLint startRow = 0;
+ GLint stopRow = 0;
+ GLint stepRow = 0;
+
+ GLfloat backgroundRotation = 0;
+
+ GLfloat barPos = 0;
+ GLfloat rowPos = 0;
+
+ static QVector3D selection = QVector3D(0, 0, 0);
+
+ // Specify viewport
+ glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(),
+ d_ptr->m_sceneViewPort.width(), d_ptr->m_sceneViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+ projectionMatrix.perspective(45.0f, (GLfloat)d_ptr->m_sceneViewPort.width()
+ / (GLfloat)d_ptr->m_sceneViewPort.height(), 0.1f, 100.0f);
+
+ // Calculate view matrix
+ QMatrix4x4 viewMatrix = CameraHelper::calculateViewMatrix(d_ptr->m_mousePos,
+ d_ptr->m_zoomLevel
+ * d_ptr->m_zoomAdjustment,
+ d_ptr->m_sceneViewPort.width(),
+ d_ptr->m_sceneViewPort.height());
+
+ // Calculate drawing order
+ // Draw order is reversed to optimize amount of drawing (ie. draw front objects first, depth test handles not needing to draw objects behind them)
+ if (viewMatrix.row(0).x() >= 0) {
+ startRow = 0;
+ stopRow = d_ptr->m_sampleCount.second;
+ stepRow = 1;
+ d_ptr->m_zFlipped = false;
+ } else {
+ startRow = d_ptr->m_sampleCount.second - 1;
+ stopRow = -1;
+ stepRow = -1;
+ d_ptr->m_zFlipped = true;
+ }
+ if (viewMatrix.row(0).z() <= 0) {
+ startBar = 0;
+ stopBar = d_ptr->m_sampleCount.first;
+ stepBar = 1;
+ d_ptr->m_xFlipped = false;
+ } else {
+ startBar = d_ptr->m_sampleCount.first - 1;
+ stopBar = -1;
+ stepBar = -1;
+ d_ptr->m_xFlipped = true;
+ }
+
+ // calculate background rotation based on view matrix rotation
+ if (viewMatrix.row(0).x() >= 0 && viewMatrix.row(0).z() <= 0)
+ backgroundRotation = 270.0f;
+ else if (viewMatrix.row(0).x() > 0 && viewMatrix.row(0).z() > 0)
+ backgroundRotation = 180.0f;
+ else if (viewMatrix.row(0).x() <= 0 && viewMatrix.row(0).z() >= 0)
+ backgroundRotation = 90.0f;
+ else if (viewMatrix.row(0).x() < 0 && viewMatrix.row(0).z() < 0)
+ backgroundRotation = 0.0f;
+
+ // Get light position (rotate light with camera, a bit above it (as set in defaultLightPos))
+ QVector3D lightPos = CameraHelper::calculateLightPosition(defaultLightPos);
+ //lightPos = QVector3D(0.0f, 4.0f, zComp); // center of bars, 4.0f above - for testing
+
+ // Skip depth rendering if we're in zoom mode
+ // TODO: Fix this, causes problems if depth rendering is off in zoom mode
+ // Introduce regardless of shadow quality to simplify logic
+ QMatrix4x4 depthViewMatrix;
+ QMatrix4x4 depthProjectionMatrix;
+
+ if (d_ptr->m_shadowQuality > ShadowNone/*!d_ptr->m_zoomActivated*/) {
+ // Render scene into a depth texture for using with shadow mapping
+ // Bind depth shader
+ d_ptr->m_depthShader->bind();
+
+ // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows.
+ glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(),
+ d_ptr->m_sceneViewPort.width() * d_ptr->m_shadowQuality,
+ d_ptr->m_sceneViewPort.height() * d_ptr->m_shadowQuality);
+
+ // Enable drawing to framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, d_ptr->m_depthFrameBuffer);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // Set front face culling to reduce self-shadowing issues
+ glCullFace(GL_FRONT);
+
+ // Get the depth view matrix
+ // It may be possible to hack lightPos here if we want to make some tweaks to shadow
+ depthViewMatrix.lookAt(lightPos, QVector3D(0.0f, 1.0f - d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above? That causes the scene to be not drawn from above -> must be fixed
+ //qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3);
+ // Set the depth projection matrix
+#ifdef USE_WIDER_SHADOWS
+ // Use this for a bit exaggerated shadows
+ depthProjectionMatrix.perspective(20.0f, (GLfloat)d_ptr->m_sceneViewPort.width()
+ / (GLfloat)d_ptr->m_sceneViewPort.height(), 3.0f, 100.0f);
+#else
+ // Use these for normal shadows, with the light further away
+ depthProjectionMatrix = projectionMatrix;
+#endif
+ // Draw bars to depth buffer
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ if (!d_ptr->m_dataSet->d_ptr->getRow(row))
+ continue;
+ QDataItem *item = d_ptr->m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar);
+ if (!item)
+ continue;
+
+ GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer;
+ // skip shadows for barHeight < 0 (for now)
+ // skip shadows for 0 -height bars
+ if (barHeight <= 0)
+ continue;
+
+ //if (barHeight < 0)
+ // glCullFace(GL_FRONT);
+ //else
+ // glCullFace(GL_BACK);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ barPos = (bar + 1) * (d_ptr->m_barSpacing.width());
+ rowPos = (row + 1) * (d_ptr->m_barSpacing.height());
+
+ modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ barHeight - d_ptr->m_yAdjustment,
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor
+ + zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ));
+
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ d_ptr->m_depthShader->setUniformValue(d_ptr->m_depthShader->MVP(), MVPMatrix);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(d_ptr->m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf());
+ glVertexAttribPointer(d_ptr->m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0,
+ (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(d_ptr->m_depthShader->posAtt());
+ }
+ }
+
+ // Disable drawing to framebuffer (= enable drawing to screen)
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // Release depth shader
+ d_ptr->m_depthShader->release();
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it)
+ d_ptr->m_labelShader->bind();
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ d_ptr->m_labelShader->setUniformValue(d_ptr->m_labelShader->MVP(), MVPMatrix);
+ d_ptr->m_drawer->drawObject(d_ptr->m_labelShader, d_ptr->m_labelObj,
+ d_ptr->m_depthTexture);
+ glDisable(GL_TEXTURE_2D);
+ d_ptr->m_labelShader->release();
+#endif
+ // Reset culling to normal
+ glCullFace(GL_BACK);
+
+ // Revert to original viewport
+ glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(),
+ d_ptr->m_sceneViewPort.width(), d_ptr->m_sceneViewPort.height());
+ }
+
+ // Skip selection mode drawing if we're zoomed or have no selection mode
+ if (!d_ptr->m_zoomActivated && d_ptr->m_selectionMode > ModeNone) {
+ // Bind selection shader
+ d_ptr->m_selectionShader->bind();
+
+ // Draw bars to selection buffer
+#ifndef USE_HAX0R_SELECTION
+ glBindFramebuffer(GL_FRAMEBUFFER, d_ptr->m_selectionFrameBuffer);
+ glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f); // Set clear color to white
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer
+#endif
+ glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ if (!d_ptr->m_dataSet->d_ptr->getRow(row))
+ continue;
+ QDataItem *item = d_ptr->m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar);
+ if (!item)
+ continue;
+
+ GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer;
+
+ if (barHeight < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ barPos = (bar + 1) * (d_ptr->m_barSpacing.width());
+ rowPos = (row + 1) * (d_ptr->m_barSpacing.height());
+
+ modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ barHeight - d_ptr->m_yAdjustment,
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor
+ + zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+
+ // TODO: Save position to qdataitem, so that we don't need to calculate it each time?
+
+ // add +2 to avoid black
+ QVector3D barColor = QVector3D((GLdouble)(row + 2)
+ / (GLdouble)(d_ptr->m_sampleCount.second + 2),
+ (GLdouble)(bar + 2)
+ / (GLdouble)(d_ptr->m_sampleCount.first + 2),
+ 0.0);
+
+ d_ptr->m_selectionShader->setUniformValue(d_ptr->m_selectionShader->MVP(),
+ MVPMatrix);
+ d_ptr->m_selectionShader->setUniformValue(d_ptr->m_selectionShader->color(),
+ barColor);
+
+#ifdef USE_HAX0R_SELECTION
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(d_ptr->m_selectionShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf());
+ glVertexAttribPointer(d_ptr->m_selectionShader->posAtt(),
+ 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(),
+ GL_UNSIGNED_SHORT, (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(d_ptr->m_selectionShader->posAtt());
+#else
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(d_ptr->m_selectionShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf());
+ glVertexAttribPointer(d_ptr->m_selectionShader->posAtt(),
+ 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(d_ptr->m_selectionShader->posAtt());
+#endif
+ }
+ }
+ glEnable(GL_DITHER);
+
+ // Read color under cursor
+ if (Q3DBarsPrivate::MouseOnScene == d_ptr->m_mousePressed)
+ selection = Utils::getSelection(d_ptr->m_mousePos, height());
+
+#ifndef USE_HAX0R_SELECTION
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+
+ // Release selection shader
+ d_ptr->m_selectionShader->release();
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ glCullFace(GL_BACK);
+ d_ptr->m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.0f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ d_ptr->m_labelShader->setUniformValue(d_ptr->m_labelShader->MVP(), MVPMatrix);
+ d_ptr->m_drawer->drawObject(d_ptr->m_labelShader, d_ptr->m_labelObj, true,
+ d_ptr->m_selectionTexture);
+ glDisable(GL_TEXTURE_2D);
+ d_ptr->m_labelShader->release();
+#endif
+
+#ifdef USE_HAX0R_SELECTION
+ // Set clear color
+ QVector3D clearColor = Utils::vectorFromColor(d_ptr->m_theme->m_windowColor);
+ glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f);
+ // Clear after selection
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+#endif
+ }
+
+ // Bind bar shader
+ d_ptr->m_barShader->bind();
+
+ // Enable texturing
+ glEnable(GL_TEXTURE_2D);
+
+ // Draw bars
+ if (!d_ptr->m_zoomActivated && d_ptr->m_zoomSelection)
+ d_ptr->m_zoomSelection->d_ptr->clear();
+ bool barSelectionFound = false;
+ for (int row = startRow; row != stopRow; row += stepRow) {
+ for (int bar = startBar; bar != stopBar; bar += stepBar) {
+ if (!d_ptr->m_dataSet->d_ptr->getRow(row))
+ continue;
+ QDataItem *item = d_ptr->m_dataSet->d_ptr->getRow(row)->d_ptr->getItem(bar);
+ if (!item)
+ continue;
+
+ GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer;
+
+ if (barHeight < 0)
+ glCullFace(GL_FRONT);
+ else
+ glCullFace(GL_BACK);
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 itModelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+
+ barPos = (bar + 1) * (d_ptr->m_barSpacing.width());
+ rowPos = (row + 1) * (d_ptr->m_barSpacing.height());
+ modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ barHeight - d_ptr->m_yAdjustment,
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor + zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ));
+ itModelMatrix.scale(QVector3D(d_ptr->m_scaleX, barHeight, d_ptr->m_scaleZ));
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ QVector3D baseColor = Utils::vectorFromColor(d_ptr->m_theme->m_baseColor);
+ QVector3D heightColor = Utils::vectorFromColor(d_ptr->m_theme->m_heightColor)
+ * barHeight;
+ QVector3D depthColor = Utils::vectorFromColor(d_ptr->m_theme->m_depthColor)
+ * (float(row) / GLfloat(d_ptr->m_sampleCount.second));
+
+ QVector3D barColor = baseColor + heightColor + depthColor;
+
+ GLfloat lightStrength = d_ptr->m_theme->m_lightStrength;
+ if (d_ptr->m_selectionMode > ModeNone) {
+ Q3DBarsPrivate::SelectionType selectionType = d_ptr->isSelected(row, bar,
+ selection);
+ switch (selectionType) {
+ case Q3DBarsPrivate::SelectionBar: {
+ barColor = Utils::vectorFromColor(d_ptr->m_theme->m_highlightBarColor);
+ lightStrength = d_ptr->m_theme->m_highlightLightStrength;
+ //if (d_ptr->m_mousePressed) {
+ // qDebug() << "selected object:" << barIndex << "( row:" << row + 1 << ", column:" << bar + 1 << ")";
+ // qDebug() << "object position:" << modelMatrix.column(3).toVector3D();
+ //}
+ // Insert data to QDataItem. We have no ownership, don't delete the previous one
+ if (!d_ptr->m_zoomActivated) {
+ d_ptr->m_selectedBar = item;
+ if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > row
+ && d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > bar) {
+ d_ptr->m_selectedBar->setPosition(
+ QPoint(d_ptr->m_dataSet->d_ptr->rowLabelItems().size()
+ - row - 1,
+ d_ptr->m_dataSet->d_ptr->columnLabelItems().size()
+ - bar - 1));
+ }
+ item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D());
+ barSelectionFound = true;
+ if (d_ptr->m_selectionMode >= ModeZoomRow) {
+ item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D());
+ d_ptr->m_zoomSelection->addItem(item);
+ }
+ }
+ break;
+ }
+ case Q3DBarsPrivate::SelectionRow: {
+ // Current bar is on the same row as the selected bar
+ barColor = Utils::vectorFromColor(d_ptr->m_theme->m_highlightRowColor);
+ lightStrength = d_ptr->m_theme->m_highlightLightStrength;
+ if (!d_ptr->m_zoomActivated && ModeZoomRow == d_ptr->m_selectionMode) {
+ item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D());
+ d_ptr->m_zoomSelection->addItem(item);
+ if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > row) {
+ d_ptr->m_zoomSelection->d_ptr->setLabelItem(
+ d_ptr->m_dataSet->d_ptr->rowLabelItems().at(
+ d_ptr->m_dataSet->d_ptr->rowLabelItems().size()
+ - row - 1));
+ }
+ }
+ break;
+ }
+ case Q3DBarsPrivate::SelectionColumn: {
+ // Current bar is on the same column as the selected bar
+ barColor = Utils::vectorFromColor(d_ptr->m_theme->m_highlightColumnColor);
+ lightStrength = d_ptr->m_theme->m_highlightLightStrength;
+ if (!d_ptr->m_zoomActivated && ModeZoomColumn == d_ptr->m_selectionMode) {
+ item->d_ptr->setTranslation(modelMatrix.column(3).toVector3D());
+ d_ptr->m_zoomSelection->addItem(item);
+ if (d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > bar) {
+ d_ptr->m_zoomSelection->d_ptr->setLabelItem(
+ d_ptr->m_dataSet->d_ptr->columnLabelItems().at(
+ d_ptr->m_dataSet->d_ptr->columnLabelItems().size()
+ - bar - 1));
+ }
+ }
+ break;
+ }
+ case Q3DBarsPrivate::SelectionNone: {
+ // Current bar is not selected, nor on a row or column
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ if (barHeight != 0) {
+ // Set shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightP(), lightPos);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->view(), viewMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(),
+ itModelMatrix.transposed().inverted());
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->color(), barColor);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->ambientS(),
+ d_ptr->m_theme->m_ambientStrength);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ lightStrength / 10.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj,
+ 0, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj);
+ }
+ }
+ }
+ }
+
+ // Release bar shader
+ d_ptr->m_barShader->release();
+
+ // Bind background shader
+ d_ptr->m_backgroundShader->bind();
+
+ glCullFace(GL_BACK);
+
+ // Draw background
+ if (d_ptr->m_backgroundObj) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(0.0f, 1.0f - d_ptr->m_yAdjustment, zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor,
+ 1.0f,
+ d_ptr->m_columnDepth / d_ptr->m_scaleFactor));
+ modelMatrix.rotate(backgroundRotation, 0.0f, 1.0f, 0.0f);
+ itModelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor,
+ 1.0f,
+ d_ptr->m_columnDepth / d_ptr->m_scaleFactor));
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+
+ QVector3D backgroundColor = Utils::vectorFromColor(d_ptr->m_theme->m_backgroundColor);
+
+ // Set shader bindings
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightP(),
+ lightPos);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->view(),
+ viewMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->model(),
+ modelMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->MVP(),
+ MVPMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->color(),
+ backgroundColor);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->ambientS(),
+ d_ptr->m_theme->m_ambientStrength);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightS(),
+ d_ptr->m_theme->m_lightStrength / 10.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj,
+ 0, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightS(),
+ d_ptr->m_theme->m_lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj);
+ }
+ }
+
+ // Disable textures
+ glDisable(GL_TEXTURE_2D);
+
+ // Release background shader
+ d_ptr->m_backgroundShader->release();
+
+ // Draw grid lines
+ if (d_ptr->m_gridEnabled) {
+ // Bind bar shader
+ d_ptr->m_barShader->bind();
+
+ // Set unchanging shader bindings
+ QVector3D barColor = Utils::vectorFromColor(d_ptr->m_theme->m_gridLine);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightP(), lightPos);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->view(), viewMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->color(), barColor);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->ambientS(),
+ d_ptr->m_theme->m_ambientStrength);
+
+ // Floor lines: rows
+ for (GLfloat row = 0.0f; row <= d_ptr->m_sampleCount.second; row++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ rowPos = (row + 0.5f) * (d_ptr->m_barSpacing.height());
+ modelMatrix.translate(0.0f, -d_ptr->m_yAdjustment,
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor + zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+ itModelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength / 10.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj,
+ 0, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj);
+ }
+ }
+
+ // Floor lines: columns
+ for (GLfloat bar = 0.0f; bar <= d_ptr->m_sampleCount.first; bar++) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ barPos = (bar + 0.5f) * (d_ptr->m_barSpacing.width());
+ modelMatrix.translate((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ -d_ptr->m_yAdjustment, zComp);
+ modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ d_ptr->m_columnDepth / d_ptr->m_scaleFactor));
+ itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ d_ptr->m_columnDepth / d_ptr->m_scaleFactor));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength / 10.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj,
+ 0, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj);
+ }
+ }
+
+ // Wall lines: back wall
+ GLfloat heightStep = d_ptr->m_heightNormalizer / 5.0f; // default to 5 lines
+
+ if (d_ptr->m_tickCount > 0)
+ heightStep = d_ptr->m_tickStep;
+
+ for (GLfloat lineHeight = heightStep; lineHeight <= d_ptr->m_heightNormalizer;
+ lineHeight += heightStep) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (d_ptr->m_zFlipped) {
+ modelMatrix.translate(0.0f,
+ 2.0f * lineHeight / d_ptr->m_heightNormalizer
+ - d_ptr->m_yAdjustment,
+ d_ptr->m_columnDepth / d_ptr->m_scaleFactor + zComp);
+ } else {
+ modelMatrix.translate(0.0f,
+ 2.0f * lineHeight / d_ptr->m_heightNormalizer
+ - d_ptr->m_yAdjustment,
+ -d_ptr->m_columnDepth / d_ptr->m_scaleFactor + zComp);
+ }
+ modelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+ itModelMatrix.scale(QVector3D(d_ptr->m_rowWidth / d_ptr->m_scaleFactor, gridLineWidth,
+ gridLineWidth));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength / 10.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj,
+ 0, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj);
+ }
+ }
+
+ // Wall lines: side wall
+ for (GLfloat lineHeight = heightStep; lineHeight <= d_ptr->m_heightNormalizer;
+ lineHeight += heightStep) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ if (d_ptr->m_xFlipped) {
+ modelMatrix.translate(d_ptr->m_rowWidth / d_ptr->m_scaleFactor,
+ 2.0f * lineHeight / d_ptr->m_heightNormalizer
+ - d_ptr->m_yAdjustment,
+ zComp);
+ } else {
+ modelMatrix.translate(-d_ptr->m_rowWidth / d_ptr->m_scaleFactor,
+ 2.0f * lineHeight / d_ptr->m_heightNormalizer
+ - d_ptr->m_yAdjustment,
+ zComp);
+ }
+ modelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ d_ptr->m_columnDepth / d_ptr->m_scaleFactor));
+ itModelMatrix.scale(QVector3D(gridLineWidth, gridLineWidth,
+ d_ptr->m_columnDepth / d_ptr->m_scaleFactor));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set the rest of the shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength / 10.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj,
+ 0, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ d_ptr->m_theme->m_lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_gridLineObj);
+ }
+ }
+
+ // Release bar shader
+ d_ptr->m_barShader->release();
+ }
+
+ // TODO: Draw y labels
+
+ // Generate label textures for zoom selection if m_updateLabels is set
+ if (d_ptr->m_zoomActivated && d_ptr->m_updateLabels) {
+ // Create label textures
+ for (int col = 0; col < d_ptr->m_zoomSelection->d_ptr->row().size(); col++) {
+ QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(col);
+ d_ptr->m_drawer->generateLabelTexture(item);
+ }
+ }
+
+ // Handle zoom activation and label drawing
+ if (!barSelectionFound) {
+ // We have no ownership, don't delete. Just NULL the pointer.
+ d_ptr->m_selectedBar = NULL;
+ if (d_ptr->m_zoomActivated && Q3DBarsPrivate::MouseOnOverview == d_ptr->m_mousePressed) {
+ d_ptr->m_sceneViewPort = QRect(0, 0, width(), height());
+ d_ptr->m_zoomActivated = false;
+ }
+ } else if (d_ptr->m_selectionMode >= ModeZoomRow
+ && Q3DBarsPrivate::MouseOnScene == d_ptr->m_mousePressed) {
+ // Activate zoom mode
+ d_ptr->m_zoomActivated = true;
+ d_ptr->m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5);
+
+ // Create label textures
+ for (int col = 0; col < d_ptr->m_zoomSelection->d_ptr->row().size(); col++) {
+ QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(col);
+ d_ptr->m_drawer->generateLabelTexture(item);
+ }
+ } else {
+ // Print value of selected bar
+ static QDataItem *prevItem = d_ptr->m_selectedBar;
+ d_ptr->m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+#ifndef DISPLAY_FULL_DATA_ON_SELECTION
+ // Draw just the value string of the selected bar
+ if (prevItem != d_ptr->m_selectedBar || d_ptr->m_updateLabels) {
+ d_ptr->m_drawer->generateLabelTexture(d_ptr->m_selectedBar);
+ prevItem = d_ptr->m_selectedBar;
+ }
+
+ d_ptr->m_drawer->drawLabel(*d_ptr->m_selectedBar, d_ptr->m_selectedBar->d_ptr->label(),
+ viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true);
+#else
+ static bool firstSelection = true;
+ // Draw the value string followed by row label and column label
+ LabelItem labelItem = d_ptr->m_selectedBar->d_ptr->selectionLabel();
+ if (firstSelection || prevItem != d_ptr->m_selectedBar || d_ptr->m_updateLabels) {
+ QString labelText = d_ptr->m_selectedBar->d_ptr->valueStr();
+ if ((d_ptr->m_dataSet->d_ptr->columnLabels().size()
+ > d_ptr->m_selectedBar->d_ptr->position().y())
+ && (d_ptr->m_dataSet->d_ptr->rowLabels().size()
+ > d_ptr->m_selectedBar->d_ptr->position().x())) {
+ labelText.append(QStringLiteral(" ("));
+ labelText.append(d_ptr->m_dataSet->d_ptr->rowLabels().at(
+ d_ptr->m_selectedBar->d_ptr->position().x()));
+ labelText.append(QStringLiteral(", "));
+ labelText.append(d_ptr->m_dataSet->d_ptr->columnLabels().at(
+ d_ptr->m_selectedBar->d_ptr->position().y()));
+ labelText.append(QStringLiteral(")"));
+ //qDebug() << labelText;
+ }
+ d_ptr->m_drawer->generateLabelItem(&labelItem, labelText);
+ d_ptr->m_selectedBar->d_ptr->setSelectionLabel(labelItem);
+ prevItem = d_ptr->m_selectedBar;
+ firstSelection = false;
+ }
+
+ d_ptr->m_drawer->drawLabel(*d_ptr->m_selectedBar, labelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true, false);
+#endif
+ glDisable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone)
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+
+ // Release label shader
+ d_ptr->m_labelShader->release();
+
+ // Reset label update flag; they should have been updated when we get here
+ d_ptr->m_updateLabels = false;
+ }
+
+ // TODO: Calculations done temporarily here. When optimizing, move to after data set addition? Keep drawing of the labels here.
+ // Bind label shader
+ d_ptr->m_labelShader->bind();
+
+ glEnable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ // Calculate the positions for row and column labels and store them into QDataItems (and QDataRows?)
+ for (int row = 0; row != d_ptr->m_sampleCount.second; row += 1) {
+ // Go through all rows and get position of max+1 or min-1 column, depending on x flip
+ // We need only positions for them, labels have already been generated at QDataSet. Just add LabelItems
+ rowPos = (row + 1) * (d_ptr->m_barSpacing.height());
+ barPos = 0;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignRight;
+ if (d_ptr->m_zFlipped)
+ rotLabelY = 180.0f;
+ if (d_ptr->m_xFlipped) {
+ barPos = (d_ptr->m_sampleCount.first + 1) * (d_ptr->m_barSpacing.width());
+ alignment = Qt::AlignLeft;
+ }
+ QVector3D labelPos = QVector3D((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ -d_ptr->m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor
+ + zComp);
+
+ // TODO: Try it; draw the label here
+
+ // Create a data item
+ QDataItem *label = new QDataItem();
+ label->d_ptr->setTranslation(labelPos);
+ if (d_ptr->m_dataSet->d_ptr->rowLabelItems().size() > row) {
+ label->d_ptr->setLabel(d_ptr->m_dataSet->d_ptr->rowLabelItems().at(
+ d_ptr->m_dataSet->d_ptr->rowLabelItems().size() - row - 1));
+ }
+
+ //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << d_ptr->m_dataSet->d_ptr->rowLabels().at(row);
+
+ d_ptr->m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true, true, LabelMid, alignment);
+
+ delete label;
+ }
+ for (int bar = 0; bar != d_ptr->m_sampleCount.first; bar += 1) {
+ // Go through all columns and get position of max+1 or min-1 row, depending on z flip
+ // We need only positions for them, labels have already been generated at QDataSet. Just add LabelItems
+ barPos = (bar + 1) * (d_ptr->m_barSpacing.width());
+ rowPos = 0;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 90.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (d_ptr->m_xFlipped)
+ rotLabelY = -90.0f;
+ if (d_ptr->m_zFlipped) {
+ rowPos = (d_ptr->m_sampleCount.second + 1) * (d_ptr->m_barSpacing.height());
+ alignment = Qt::AlignRight;
+ }
+ QVector3D labelPos = QVector3D((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ -d_ptr->m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor
+ + zComp);
+
+ // TODO: Try it; draw the label here
+
+ // Create a data item
+ QDataItem *label = new QDataItem();
+ label->d_ptr->setTranslation(labelPos);
+ if (d_ptr->m_dataSet->d_ptr->columnLabelItems().size() > bar) {
+ label->d_ptr->setLabel(d_ptr->m_dataSet->d_ptr->columnLabelItems().at(
+ d_ptr->m_dataSet->d_ptr->columnLabelItems().size()
+ - bar - 1));
+ }
+
+ //qDebug() << "labelPos, col" << bar + 1 << ":" << labelPos << d_ptr->m_dataSet->d_ptr->columnLabels().at(bar);
+
+ d_ptr->m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true, true, LabelMid, alignment);
+
+ delete label;
+ }
+ glDisable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone)
+ glDisable(GL_BLEND);
+
+ // Release label shader
+ d_ptr->m_labelShader->release();
+}
+
+void Q3DBars::mousePressEvent(QMouseEvent *event)
+{
+ if (Qt::LeftButton == event->button()) {
+ if (d_ptr->m_zoomActivated) {
+ if (event->pos().x() <= d_ptr->m_sceneViewPort.width()
+ && event->pos().y() <= d_ptr->m_sceneViewPort.height()) {
+ d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnOverview;
+ //qDebug() << "Mouse pressed on overview";
+ } else {
+ d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnZoom;
+ //qDebug() << "Mouse pressed on zoom";
+ }
+ } else {
+ d_ptr->m_mousePressed = Q3DBarsPrivate::MouseOnScene;
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ d_ptr->m_mousePos = event->pos();
+ //qDebug() << "Mouse pressed on scene";
+ }
+ } else if (Qt::MiddleButton == event->button()) {
+ // reset rotations
+ d_ptr->m_mousePos = QPoint(0, 0);
+ } else if (Qt::RightButton == event->button()) {
+ d_ptr->m_mousePressed = Q3DBarsPrivate::MouseRotating;
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ d_ptr->m_mousePos = event->pos();
+ }
+ CameraHelper::updateMousePos(d_ptr->m_mousePos);
+}
+
+void Q3DBars::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (Q3DBarsPrivate::MouseRotating == d_ptr->m_mousePressed) {
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ d_ptr->m_mousePos = event->pos();
+ CameraHelper::updateMousePos(event->pos());
+ }
+ d_ptr->m_mousePressed = Q3DBarsPrivate::MouseNone;
+}
+
+void Q3DBars::mouseMoveEvent(QMouseEvent *event)
+{
+ if (Q3DBarsPrivate::MouseRotating == d_ptr->m_mousePressed)
+ d_ptr->m_mousePos = event->pos();
+}
+
+void Q3DBars::wheelEvent(QWheelEvent *event)
+{
+ if (d_ptr->m_zoomLevel > 100)
+ d_ptr->m_zoomLevel += event->angleDelta().y() / 12;
+ else if (d_ptr->m_zoomLevel > 50)
+ d_ptr->m_zoomLevel += event->angleDelta().y() / 60;
+ else
+ d_ptr->m_zoomLevel += event->angleDelta().y() / 120;
+ if (d_ptr->m_zoomLevel > 500)
+ d_ptr->m_zoomLevel = 500;
+ else if (d_ptr->m_zoomLevel < 10)
+ d_ptr->m_zoomLevel = 10;
+}
+
+void Q3DBars::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+
+ // Set view port
+ if (d_ptr->m_zoomActivated)
+ d_ptr->m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5);
+ else
+ d_ptr->m_sceneViewPort = QRect(0, 0, width(), height());
+ d_ptr->m_zoomViewPort = QRect(0, 0, width(), height());
+
+ // Calculate zoom level based on aspect ratio
+ GLfloat div;
+ GLfloat zoomAdjustment;
+ div = qMin(width(), height());
+ zoomAdjustment = defaultRatio * ((width() / div) / (height() / div));
+ //qDebug() << "zoom adjustment" << zoomAdjustment;
+ d_ptr->m_zoomAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f
+
+ // Re-init selection buffer
+ d_ptr->initSelectionBuffer();
+
+ // Re-init depth buffer
+ d_ptr->initDepthBuffer();
+}
+
+void Q3DBars::setBarSpecs(QSizeF thickness, QSizeF spacing, bool relative)
+{
+ d_ptr->m_barThickness = thickness;
+ if (relative) {
+ d_ptr->m_barSpacing.setWidth((thickness.width() * 2) * (spacing.width() + 1.0f));
+ d_ptr->m_barSpacing.setHeight((thickness.height() * 2) * (spacing.height() + 1.0f));
+ } else {
+ d_ptr->m_barSpacing = thickness * 2 + spacing * 2;
+ }
+ // Calculate here and at setting sample space
+ d_ptr->calculateSceneScalingFactors();
+}
+
+void Q3DBars::setBarType(BarStyle style, bool smooth)
+{
+ if (style == Bars) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/barSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/bar");
+ } else if (style == Pyramids) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/pyramidSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/pyramid");
+ } else if (style == Cones) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/coneSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cone");
+ } else if (style == Cylinders) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cylinderSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cylinder");
+ }
+ // Reload mesh data
+ if (d_ptr->m_isInitialized)
+ d_ptr->loadBarMesh();
+}
+
+void Q3DBars::setMeshFileName(const QString &objFileName)
+{
+ d_ptr->m_objFile = objFileName;
+}
+
+void Q3DBars::setupSampleSpace(int samplesRow, int samplesColumn, const QString &labelRow,
+ const QString &labelColumn, const QString &labelHeight)
+{
+ // Delete previous data set
+ delete d_ptr->m_dataSet;
+ d_ptr->m_dataSet = new QDataSet();
+ d_ptr->m_sampleCount = qMakePair(samplesRow, samplesColumn);
+ d_ptr->m_dataSet->setLabels(labelRow, labelColumn, labelHeight);
+ // TODO: Invent "idiotproof" max scene size formula..
+ // This seems to work ok if spacing is not negative (and row/column or column/row ratio is not too high)
+ d_ptr->m_maxSceneSize = 2 * qSqrt(samplesRow * samplesColumn);
+ //qDebug() << "maxSceneSize" << d_ptr->m_maxSceneSize;
+ // Calculate here and at setting bar specs
+ d_ptr->calculateSceneScalingFactors();
+ d_ptr->m_axisLabelX = labelRow;
+ d_ptr->m_axisLabelZ = labelColumn;
+ d_ptr->m_axisLabelY = labelHeight;
+}
+
+void Q3DBars::setCameraPreset(CameraPreset preset)
+{
+ CameraHelper::setCameraPreset(preset);
+}
+
+void Q3DBars::setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance)
+{
+ d_ptr->m_horizontalRotation = qBound(-180.0f, horizontal, 180.0f);
+ d_ptr->m_verticalRotation = qBound(0.0f, vertical, 90.0f);
+ d_ptr->m_zoomLevel = qBound(10, distance, 500);
+ CameraHelper::setCameraRotation(QPointF(d_ptr->m_horizontalRotation,
+ d_ptr->m_verticalRotation));
+ //qDebug() << "camera rotation set to" << d_ptr->m_horizontalRotation << d_ptr->m_verticalRotation;
+}
+
+void Q3DBars::setTheme(ColorTheme theme)
+{
+ d_ptr->m_theme->useTheme(theme);
+ d_ptr->m_drawer->setTheme(*d_ptr->m_theme);
+ // Re-initialize shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+}
+
+void Q3DBars::setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, bool uniform)
+{
+ d_ptr->m_theme->m_baseColor = baseColor;
+ d_ptr->m_theme->m_heightColor = heightColor;
+ d_ptr->m_theme->m_depthColor = depthColor;
+ //qDebug() << "colors:" << d_ptr->m_baseColor << d_ptr->m_heightColor << d_ptr->m_depthColor;
+ if (d_ptr->m_theme->m_uniformColor != uniform) {
+ // Re-initialize shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ }
+ d_ptr->m_theme->m_uniformColor = uniform;
+}
+
+void Q3DBars::setSelectionMode(SelectionMode mode)
+{
+ d_ptr->m_selectionMode = mode;
+ // Disable zoom if mode changes
+ d_ptr->m_zoomActivated = false;
+ d_ptr->m_sceneViewPort = QRect(0, 0, width(), height());
+ // Create zoom selection if there isn't one
+ if (mode >= ModeZoomRow && !d_ptr->m_zoomSelection)
+ d_ptr->m_zoomSelection = new QDataRow();
+}
+
+void Q3DBars::setWindowTitle(const QString &title)
+{
+ setTitle(title);
+}
+
+void Q3DBars::setFontSize(float fontsize)
+{
+ d_ptr->m_font.setPointSizeF(fontsize);
+ d_ptr->m_drawer->setFont(d_ptr->m_font);
+}
+
+void Q3DBars::setFont(const QFont &font)
+{
+ d_ptr->m_font = font;
+ d_ptr->m_drawer->setFont(font);
+}
+
+void Q3DBars::setLabelTransparency(LabelTransparency transparency)
+{
+ d_ptr->m_labelTransparency = transparency;
+ d_ptr->m_drawer->setTransparency(transparency);
+}
+
+void Q3DBars::setGridEnabled(bool enable)
+{
+ d_ptr->m_gridEnabled = enable;
+}
+
+void Q3DBars::setTickCount(GLint tickCount, GLfloat step, GLfloat minimum)
+{
+ d_ptr->m_tickCount = tickCount;
+ d_ptr->m_tickStep = step;
+ if (tickCount > 0 && step > 0) {
+ d_ptr->m_heightNormalizer = tickCount * step;
+ d_ptr->calculateHeightAdjustment(QPair<float, float>(minimum, d_ptr->m_heightNormalizer));
+ }
+}
+
+void Q3DBars::setShadowQuality(ShadowQuality quality)
+{
+ d_ptr->m_shadowQuality = quality;
+ switch (quality) {
+ case ShadowLow:
+ d_ptr->m_shadowQualityToShader = 33.3f;
+ break;
+ case ShadowMedium:
+ d_ptr->m_shadowQualityToShader = 100.0f;
+ break;
+ case ShadowHigh:
+ d_ptr->m_shadowQualityToShader = 200.0f;
+ break;
+ default:
+ d_ptr->m_shadowQualityToShader = 0.0f;
+ break;
+ }
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Re-init depth buffer
+ d_ptr->initDepthBuffer();
+ // Re-init shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ } else {
+ // Re-init shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragmentColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+}
+
+void Q3DBars::addDataRow(const QVector<float> &dataRow, const QString &labelRow,
+ const QVector<QString> &labelsColumn)
+{
+ // Convert to QDataRow and add to QDataSet
+ QDataRow *row = new QDataRow(labelRow);
+ for (int i = 0; i < dataRow.size(); i++)
+ row->addItem(new QDataItem(dataRow.at(i)));
+ row->d_ptr->verifySize(d_ptr->m_sampleCount.first);
+ d_ptr->m_dataSet->addRow(row);
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues();
+ // Don't auto-adjust height if tick count is set
+ if (d_ptr->m_tickCount == 0) {
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ }
+ d_ptr->m_dataSet->setLabels(d_ptr->m_axisLabelX, d_ptr->m_axisLabelZ, d_ptr->m_axisLabelY,
+ QVector<QString>(), labelsColumn);
+ d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second);
+}
+
+void Q3DBars::addDataRow(const QVector<QDataItem*> &dataRow, const QString &labelRow,
+ const QVector<QString> &labelsColumn)
+{
+ // Convert to QDataRow and add to QDataSet
+ QDataRow *row = new QDataRow(labelRow);
+ for (int i = 0; i < dataRow.size(); i++)
+ row->addItem(dataRow.at(i));
+ row->d_ptr->verifySize(d_ptr->m_sampleCount.first);
+ d_ptr->m_dataSet->addRow(row);
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues();
+ // Don't auto-adjust height if tick count is set
+ if (d_ptr->m_tickCount == 0) {
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ }
+ d_ptr->m_dataSet->setLabels(d_ptr->m_axisLabelX, d_ptr->m_axisLabelZ, d_ptr->m_axisLabelY,
+ QVector<QString>(), labelsColumn);
+ d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second);
+}
+
+void Q3DBars::addDataRow(QDataRow *dataRow)
+{
+ QDataRow *row = dataRow;
+ // Check that the input data fits into sample space, and resize if it doesn't
+ row->d_ptr->verifySize(d_ptr->m_sampleCount.first);
+ // With each new row, the previous data row must be moved back
+ // ie. we need as many vectors as we have rows in the sample space
+ d_ptr->m_dataSet->addRow(row);
+ // if the added data pushed us over sample space, remove the oldest data set
+ d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second);
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues();
+ // Don't auto-adjust height if tick count is set
+ if (d_ptr->m_tickCount == 0) {
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ }
+}
+
+void Q3DBars::addDataSet(const QVector< QVector<float> > &data, const QVector<QString> &labelsRow,
+ const QVector<QString> &labelsColumn)
+{
+ // Copy axis labels
+ QString xAxis;
+ QString zAxis;
+ QString yAxis;
+ d_ptr->m_dataSet->d_ptr->axisLabels(&xAxis, &zAxis, &yAxis);
+ // Delete old data set
+ delete d_ptr->m_dataSet;
+ d_ptr->m_dataSet = new QDataSet();
+ // Give drawer to data set
+ d_ptr->m_dataSet->d_ptr->setDrawer(d_ptr->m_drawer);
+ // Convert to QDataRow and add to QDataSet
+ QDataRow *row;
+ for (int rowNr = 0; rowNr < data.size(); rowNr++) {
+ if (labelsRow.size() >= (rowNr + 1))
+ row = new QDataRow(labelsRow.at(rowNr));
+ else
+ row = new QDataRow();
+ for (int colNr = 0; colNr < data.at(rowNr).size(); colNr++)
+ row->addItem(new QDataItem(data.at(rowNr).at(colNr)));
+ row->d_ptr->verifySize(d_ptr->m_sampleCount.first);
+ d_ptr->m_dataSet->addRow(row);
+ row++;
+ }
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues();
+ // Don't auto-adjust height if tick count is set
+ if (d_ptr->m_tickCount == 0) {
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ }
+ d_ptr->m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn);
+ d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second);
+}
+
+void Q3DBars::addDataSet(const QVector< QVector<QDataItem*> > &data,
+ const QVector<QString> &labelsRow,
+ const QVector<QString> &labelsColumn)
+{
+ // Copy axis labels
+ QString xAxis;
+ QString zAxis;
+ QString yAxis;
+ d_ptr->m_dataSet->d_ptr->axisLabels(&xAxis, &zAxis, &yAxis);
+ // Delete old data set
+ delete d_ptr->m_dataSet;
+ d_ptr->m_dataSet = new QDataSet();
+ // Give drawer to data set
+ d_ptr->m_dataSet->d_ptr->setDrawer(d_ptr->m_drawer);
+ // Convert to QDataRow and add to QDataSet
+ QDataRow *row;
+ for (int rowNr = 0; rowNr < data.size(); rowNr++) {
+ if (labelsRow.size() >= (rowNr + 1))
+ row = new QDataRow(labelsRow.at(rowNr));
+ else
+ row = new QDataRow();
+ for (int colNr = 0; colNr < data.at(rowNr).size(); colNr++)
+ row->addItem(data.at(rowNr).at(colNr));
+ row->d_ptr->verifySize(d_ptr->m_sampleCount.first);
+ d_ptr->m_dataSet->addRow(row);
+ row++;
+ }
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues();
+ // Don't auto-adjust height if tick count is set
+ if (d_ptr->m_tickCount == 0) {
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ }
+ d_ptr->m_dataSet->setLabels(xAxis, zAxis, yAxis, labelsRow, labelsColumn);
+ d_ptr->m_dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second);
+}
+
+void Q3DBars::addDataSet(QDataSet* dataSet)
+{
+ delete d_ptr->m_dataSet;
+ // Check sizes
+ dataSet->d_ptr->verifySize(d_ptr->m_sampleCount.second, d_ptr->m_sampleCount.first);
+ // Take ownership of given set
+ d_ptr->m_dataSet = dataSet;
+ // Find highest value
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_dataSet->d_ptr->limitValues();
+ // Don't auto-adjust height if tick count is set
+ if (d_ptr->m_tickCount == 0) {
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ }
+ // Give drawer to data set
+ d_ptr->m_dataSet->d_ptr->setDrawer(d_ptr->m_drawer);
+}
+
+Q3DBarsPrivate::Q3DBarsPrivate(Q3DBars *q)
+ : q_ptr(q),
+ m_paintDevice(0),
+ m_barShader(0),
+ m_depthShader(0),
+ m_selectionShader(0),
+ m_backgroundShader(0),
+ m_labelShader(0),
+ m_barObj(0),
+ m_backgroundObj(0),
+ m_gridLineObj(0),
+ m_labelObj(0),
+ m_sampleCount(0, 0),
+ m_objFile(QStringLiteral(":/defaultMeshes/bar")),
+ m_mousePressed(MouseNone),
+ m_mousePos(QPoint(0, 0)),
+ m_zoomLevel(100),
+ m_zoomAdjustment(1.0f),
+ m_horizontalRotation(-45.0f),
+ m_verticalRotation(15.0f),
+ m_barThickness(QSizeF(0.75f, 0.75f)),
+ m_barSpacing(m_barThickness * 3.0f),
+ m_heightNormalizer(0.0f),
+ m_yAdjustment(0.0f),
+ m_rowWidth(0),
+ m_columnDepth(0),
+ m_maxDimension(0),
+ m_scaleX(0),
+ m_scaleZ(0),
+ m_scaleFactor(0),
+ m_maxSceneSize(40.0),
+ m_theme(new Theme()),
+ m_isInitialized(false),
+ m_selectionMode(ModeBar),
+ m_selectedBar(0),
+ m_zoomSelection(0),
+ m_dataSet(new QDataSet()),
+ m_axisLabelX(QStringLiteral("X")),
+ m_axisLabelZ(QStringLiteral("Z")),
+ m_axisLabelY(QStringLiteral("Y")),
+ m_sceneViewPort(0, 0, q->width(), q->height()),
+ m_zoomViewPort(0, 0, q->width(), q->height()),
+ m_zoomActivated(false),
+ m_textureHelper(new TextureHelper()),
+ m_labelTransparency(TransparencyNone),
+ m_font(QFont(QStringLiteral("Arial"))),
+ m_drawer(new Drawer(*m_theme, m_font, m_labelTransparency)),
+ m_xFlipped(false),
+ m_zFlipped(false),
+ m_bgrTexture(0),
+ m_depthTexture(0),
+ m_selectionTexture(0),
+ m_depthFrameBuffer(0),
+ m_selectionFrameBuffer(0),
+ m_selectionDepthBuffer(0),
+ m_updateLabels(false),
+ m_gridEnabled(true),
+ m_shadowQuality(ShadowLow),
+ m_shadowQualityToShader(33.3f),
+ m_tickCount(0),
+ m_tickStep(0)
+{
+ m_dataSet->d_ptr->setDrawer(m_drawer);
+ QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Q3DBarsPrivate::updateTextures);
+}
+
+Q3DBarsPrivate::~Q3DBarsPrivate()
+{
+ qDebug() << "Destroying Q3DBarsPrivate";
+#ifndef USE_HAX0R_SELECTION
+ m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer);
+ m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer);
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+#endif
+ m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer);
+ m_textureHelper->deleteTexture(&m_bgrTexture);
+ delete m_dataSet;
+ if (m_zoomSelection) {
+ m_zoomSelection->d_ptr->clear();
+ delete m_zoomSelection;
+ }
+ delete m_barShader;
+ delete m_depthShader;
+ delete m_selectionShader;
+ delete m_backgroundShader;
+ delete m_barObj;
+ delete m_backgroundObj;
+ delete m_gridLineObj;
+ delete m_textureHelper;
+ delete m_drawer;
+}
+
+void Q3DBarsPrivate::loadBarMesh()
+{
+ if (m_barObj)
+ delete m_barObj;
+ m_barObj = new ObjectHelper(m_objFile);
+ m_barObj->load();
+}
+
+void Q3DBarsPrivate::loadBackgroundMesh()
+{
+ if (m_backgroundObj)
+ delete m_backgroundObj;
+ m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/background"));
+ m_backgroundObj->load();
+}
+
+void Q3DBarsPrivate::loadGridLineMesh()
+{
+ if (m_gridLineObj)
+ delete m_gridLineObj;
+ m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar"));
+ m_gridLineObj->load();
+}
+
+void Q3DBarsPrivate::loadLabelMesh()
+{
+ if (m_labelObj)
+ delete m_labelObj;
+ m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label"));
+ m_labelObj->load();
+}
+
+void Q3DBarsPrivate::initShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_barShader)
+ delete m_barShader;
+ m_barShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader);
+ m_barShader->initialize();
+}
+
+void Q3DBarsPrivate::initSelectionShader()
+{
+ if (m_selectionShader)
+ delete m_selectionShader;
+ m_selectionShader = new ShaderHelper(q_ptr, QStringLiteral(":/shaders/vertexSelection"),
+ QStringLiteral(":/shaders/fragmentSelection"));
+ m_selectionShader->initialize();
+}
+
+void Q3DBarsPrivate::initDepthShader()
+{
+ if (m_depthShader)
+ delete m_depthShader;
+ m_depthShader = new ShaderHelper(q_ptr, QStringLiteral(":/shaders/vertexDepth"),
+ QStringLiteral(":/shaders/fragmentDepth"));
+ m_depthShader->initialize();
+}
+
+void Q3DBarsPrivate::initSelectionBuffer()
+{
+#ifndef USE_HAX0R_SELECTION
+ if (m_selectionTexture) {
+ m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer);
+ m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer);
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+ }
+ m_selectionTexture = m_textureHelper->createSelectionTexture(q_ptr->size(),
+ m_selectionFrameBuffer,
+ m_selectionDepthBuffer);
+#endif
+}
+
+void Q3DBarsPrivate::initDepthBuffer()
+{
+ if (m_depthTexture) {
+ m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer);
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ }
+ m_depthTexture = m_textureHelper->createDepthTexture(q_ptr->size(), m_depthFrameBuffer,
+ m_shadowQuality);
+}
+
+void Q3DBarsPrivate::initBackgroundShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ if (m_backgroundShader)
+ delete m_backgroundShader;
+ m_backgroundShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader);
+ m_backgroundShader->initialize();
+}
+
+void Q3DBarsPrivate::initLabelShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_labelShader)
+ delete m_labelShader;
+ m_labelShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader);
+ m_labelShader->initialize();
+}
+
+void Q3DBarsPrivate::updateTextures()
+{
+ // Drawer has changed; this flag needs to be checked when checking if we need to update labels
+ m_updateLabels = true;
+}
+
+void Q3DBarsPrivate::calculateSceneScalingFactors()
+{
+ // Calculate scene scaling and translation factors
+ m_rowWidth = ((m_sampleCount.first + 1) * m_barSpacing.width()) / 2.0f;
+ m_columnDepth = ((m_sampleCount.second + 1) * m_barSpacing.height()) / 2.0f;
+ m_maxDimension = qMax(m_rowWidth, m_columnDepth);
+ m_scaleFactor = qMin((m_sampleCount.first * (m_maxDimension / m_maxSceneSize)),
+ (m_sampleCount.second * (m_maxDimension / m_maxSceneSize)));
+ m_scaleX = m_barThickness.width() / m_scaleFactor;
+ m_scaleZ = m_barThickness.height() / m_scaleFactor;
+ //qDebug() << "m_scaleX" << m_scaleX << "m_scaleFactor" << m_scaleFactor;
+ //qDebug() << "m_scaleZ" << m_scaleZ << "m_scaleFactor" << m_scaleFactor;
+ //qDebug() << "m_rowWidth:" << m_rowWidth << "m_columnDepth:" << m_columnDepth << "m_maxDimension:" << m_maxDimension;
+}
+
+void Q3DBarsPrivate::calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits)
+{
+ // 2.0f = max difference between minimum and maximum value after scaling with m_heightNormalizer
+ m_yAdjustment = 2.0f - ((limits.second - limits.first) / m_heightNormalizer);
+ //qDebug() << m_yAdjustment;
+}
+
+Q3DBarsPrivate::SelectionType Q3DBarsPrivate::isSelected(GLint row, GLint bar,
+ const QVector3D &selection)
+{
+ //static QVector3D prevSel = selection; // TODO: For debugging
+ SelectionType isSelectedType = SelectionNone;
+#ifdef USE_HAX0R_SELECTION
+ if (selection == Utils::vectorFromColor(m_theme->m_windowColor))
+#else
+ if (selection == Utils::vectorFromColor(Qt::white))
+#endif
+ return isSelectedType; // skip window
+ QVector3D current = QVector3D((GLubyte)(((GLdouble)(row + 2) / (GLdouble)(m_sampleCount.second + 2))
+ * 255.0 + 0.49), // +0.49 to fix rounding (there are conversions from unsigned short to GLdouble and back)
+ (GLubyte)(((GLdouble)(bar + 2) / (GLdouble)(m_sampleCount.first + 2))
+ * 255.0 + 0.49), // +0.49 to fix rounding (there are conversions from unsigned short to GLdouble and back)
+ 0);
+ // TODO: For debugging
+ //if (selection != prevSel) {
+ // qDebug() << selection.x() << selection .y() << selection.z();
+ // prevSel = selection;
+ //}
+ if (current == selection)
+ isSelectedType = SelectionBar;
+ else if (current.y() == selection.y() && (m_selectionMode == ModeBarAndColumn
+ || m_selectionMode == ModeBarRowAndColumn
+ || m_selectionMode == ModeZoomColumn))
+ isSelectedType = SelectionColumn;
+ else if (current.x() == selection.x() && (m_selectionMode == ModeBarAndRow
+ || m_selectionMode == ModeBarRowAndColumn
+ || m_selectionMode == ModeZoomRow))
+ isSelectedType = SelectionRow;
+ return isSelectedType;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/q3dbars.h b/src/datavis3d/engine/q3dbars.h
new file mode 100644
index 00000000..3e490144
--- /dev/null
+++ b/src/datavis3d/engine/q3dbars.h
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DBARS_H
+#define Q3DBARS_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+#include "QtDataVis3D/qdatavis3namespace.h"
+#include "q3dwindow.h"
+
+class QOpenGLShaderProgram;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Q3DBarsPrivate;
+class QDataItem;
+class QDataRow;
+class QDataSet;
+class LabelItem;
+
+class QTCOMMERCIALDATAVIS3D_EXPORT Q3DBars : public Q3DWindow
+{
+ Q_OBJECT
+public:
+ explicit Q3DBars();
+ ~Q3DBars();
+
+ void initialize();
+ void render();
+
+ // Add a row of data. Each new row is added to the front of the sample space, moving previous
+ // rows back (if sample space is more than one row deep)
+ void addDataRow(const QVector<GLfloat> &dataRow,
+ const QString &labelRow = QString(),
+ const QVector<QString> &labelsColumn = QVector<QString>());
+ // ownership of dataItems is transferred
+ void addDataRow(const QVector<QDataItem*> &dataRow,
+ const QString &labelRow = QString(),
+ const QVector<QString> &labelsColumn = QVector<QString>());
+ // ownership of dataRow is transferred
+ void addDataRow(QDataRow *dataRow);
+
+ // Add complete data set at a time, as a vector of data rows
+ void addDataSet(const QVector< QVector<GLfloat> > &data,
+ const QVector<QString> &labelsRow = QVector<QString>(),
+ const QVector<QString> &labelsColumn = QVector<QString>());
+
+ // ownership of dataItems is transferred
+ void addDataSet(const QVector< QVector<QDataItem*> > &data,
+ const QVector<QString> &labelsRow = QVector<QString>(),
+ const QVector<QString> &labelsColumn = QVector<QString>());
+ // ownership of dataSet is transferred
+ void addDataSet(QDataSet* dataSet);
+
+ // bar thickness, spacing between bars, and is spacing relative to thickness or absolute
+ // y -component sets the thickness/spacing of z -direction
+ // With relative 0.0f means side-to-side, 1.0f = one thickness in between
+ void setBarSpecs(QSizeF thickness = QSizeF(1.0f, 1.0f),
+ QSizeF spacing = QSizeF(1.0f, 1.0f),
+ bool relative = true);
+
+ // bar type; bars (=cubes), pyramids, cones, cylinders, etc.
+ void setBarType(BarStyle style, bool smooth = false);
+
+ // override bar type with own mesh
+ void setMeshFileName(const QString &objFileName);
+
+ // how many samples per row and column, and names for axes
+ void setupSampleSpace(int samplesRow, int samplesColumn, const QString &labelRow = QString(),
+ const QString &labelColumn = QString(),
+ const QString &labelHeight = QString());
+
+ // Select preset camera placement
+ void setCameraPreset(CameraPreset preset);
+
+ // Set camera rotation if you don't want to use the presets (in horizontal (-180...180) and
+ // vertical (0...90) angles and distance in percentage (10...500))
+ void setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance = 100);
+
+ // Set theme (bar colors, shaders, window color, background colors, light intensity and text colors are affected)
+ void setTheme(ColorTheme theme);
+
+ // Set color if you don't want to use themes. Set uniform to false if you want the (height) color to change from bottom to top
+ void setBarColor(QColor baseColor, QColor heightColor, QColor depthColor, bool uniform = true);
+
+ // TODO: valon siirto / asetus
+ // Change selection mode; single bar, bar and row, bar and column, or all
+ void setSelectionMode(SelectionMode mode);
+
+ // Set window title
+ void setWindowTitle(const QString &title);
+
+ // Font size adjustment (should it be in enum (smallest, smaller, small, normal, large, larger, largest), or just GLfloat?
+ void setFontSize(GLfloat fontsize);
+
+ // Set font
+ void setFont(const QFont &font);
+
+ // Label transparency adjustment
+ void setLabelTransparency(LabelTransparency transparency);
+
+ // Enable or disable background grid
+ void setGridEnabled(bool enable);
+
+ // Adjust shadow quality
+ void setShadowQuality(ShadowQuality quality);
+
+ // Set tick count and step. Note; tickCount * step should be the maximum possible value of data set.
+ // Minimum is the absolute minimum possible value a bar can have. This is especially important to
+ // set if values can be negative.
+ void setTickCount(GLint tickCount, GLfloat step, GLfloat minimum = 0.0f);
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void wheelEvent(QWheelEvent *event);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ void drawZoomScene();
+ void drawScene();
+ QScopedPointer<Q3DBarsPrivate> d_ptr;
+ Q_DISABLE_COPY(Q3DBars)
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/q3dbars_p.h b/src/datavis3d/engine/q3dbars_p.h
new file mode 100644
index 00000000..30cdb6da
--- /dev/null
+++ b/src/datavis3d/engine/q3dbars_p.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef Q3DBARS_p_H
+#define Q3DBARS_p_H
+
+#include "qdatavis3dglobal.h"
+#include "qdatavis3namespace.h"
+#include <QOpenGLFunctions>
+#include <QFont>
+
+class QOpenGLPaintDevice;
+
+class QPoint;
+class QSizeF;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Q3DBars;
+class QDataItem;
+class QDataRow;
+class QDataSet;
+class ShaderHelper;
+class ObjectHelper;
+class TextureHelper;
+class Theme;
+class Drawer;
+
+class Q3DBarsPrivate : public QObject
+{
+public:
+ enum SelectionType {
+ SelectionNone = 0,
+ SelectionBar,
+ SelectionRow,
+ SelectionColumn
+ };
+
+ enum MousePressType {
+ MouseNone = 0,
+ MouseOnScene,
+ MouseOnOverview,
+ MouseOnZoom,
+ MouseRotating
+ };
+
+public:
+ Q3DBarsPrivate(Q3DBars *q);
+ ~Q3DBarsPrivate();
+
+ void loadBarMesh();
+ void loadBackgroundMesh();
+ void loadGridLineMesh();
+ void loadLabelMesh();
+ void initShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initSelectionShader();
+ void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initDepthShader();
+ void initSelectionBuffer();
+ void initDepthBuffer();
+ void updateTextures();
+ void calculateSceneScalingFactors();
+ void calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits);
+ SelectionType isSelected(GLint row, GLint bar, const QVector3D &selection);
+
+ Q3DBars *q_ptr;
+
+ QOpenGLPaintDevice *m_paintDevice;
+ ShaderHelper *m_barShader;
+ ShaderHelper *m_depthShader;
+ ShaderHelper *m_selectionShader;
+ ShaderHelper *m_backgroundShader;
+ ShaderHelper *m_labelShader;
+ ObjectHelper *m_barObj;
+ ObjectHelper *m_backgroundObj;
+ ObjectHelper *m_gridLineObj;
+ ObjectHelper *m_labelObj;
+ QPair<int, int> m_sampleCount;
+ QString m_objFile;
+ MousePressType m_mousePressed;
+ QPoint m_mousePos;
+ GLint m_zoomLevel;
+ GLfloat m_zoomAdjustment;
+ GLfloat m_horizontalRotation;
+ GLfloat m_verticalRotation;
+ QSizeF m_barThickness;
+ QSizeF m_barSpacing;
+ GLfloat m_heightNormalizer;
+ GLfloat m_yAdjustment;
+ GLfloat m_rowWidth;
+ GLfloat m_columnDepth;
+ GLfloat m_maxDimension;
+ GLfloat m_scaleX;
+ GLfloat m_scaleZ;
+ GLfloat m_scaleFactor;
+ GLfloat m_maxSceneSize;
+ Theme *m_theme;
+ bool m_isInitialized;
+ SelectionMode m_selectionMode;
+ QDataItem *m_selectedBar;
+ QDataRow *m_zoomSelection;
+ QDataSet *m_dataSet;
+ QString m_axisLabelX;
+ QString m_axisLabelZ;
+ QString m_axisLabelY;
+ QRect m_sceneViewPort;
+ QRect m_zoomViewPort;
+ bool m_zoomActivated;
+ TextureHelper *m_textureHelper;
+ LabelTransparency m_labelTransparency;
+ QFont m_font;
+ Drawer *m_drawer;
+ bool m_xFlipped;
+ bool m_zFlipped;
+ GLuint m_bgrTexture;
+ GLuint m_depthTexture;
+ GLuint m_selectionTexture;
+ GLuint m_depthFrameBuffer;
+ GLuint m_selectionFrameBuffer;
+ GLuint m_selectionDepthBuffer;
+ bool m_updateLabels;
+ bool m_gridEnabled;
+ ShadowQuality m_shadowQuality;
+ GLfloat m_shadowQualityToShader;
+ GLint m_tickCount;
+ GLfloat m_tickStep;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/q3dmaps.cpp b/src/datavis3d/engine/q3dmaps.cpp
new file mode 100644
index 00000000..9ac43daa
--- /dev/null
+++ b/src/datavis3d/engine/q3dmaps.cpp
@@ -0,0 +1,1525 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dmaps.h"
+#include "q3dmaps_p.h"
+#include "camerahelper_p.h"
+#include "qdataitem_p.h"
+#include "qdatarow_p.h"
+#include "qdataset_p.h"
+#include "shaderhelper_p.h"
+#include "objecthelper_p.h"
+#include "texturehelper_p.h"
+#include "theme_p.h"
+#include "utils_p.h"
+#include "drawer_p.h"
+
+#include <QMatrix4x4>
+#include <QOpenGLPaintDevice>
+#include <QPainter>
+#include <QScreen>
+#include <QMouseEvent>
+
+#include <qmath.h>
+
+#include <QDebug>
+
+//#define DISPLAY_RENDER_SPEED
+
+// Uncommenting this draws the shadow map with wider FOV than scene itself, making the light
+// seem to be closer to scene than it actually is. This way shadows look slightly better (to me anyway)
+#define USE_WIDER_SHADOWS
+
+// You can verify that depth buffer drawing works correctly by uncommenting this.
+// You should see the scene from where the light is
+//#define SHOW_DEPTH_TEXTURE_SCENE
+
+#ifdef DISPLAY_RENDER_SPEED
+#include <QTime>
+#endif
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+//#define DISPLAY_FULL_DATA_ON_SELECTION // Append selection value text with row and column labels
+
+const GLfloat gridLineWidth = 0.005f;
+GLfloat distanceMod = 0.0f;
+
+Q3DMaps::Q3DMaps()
+ : d_ptr(new Q3DMapsPrivate(this))
+{
+}
+
+Q3DMaps::~Q3DMaps()
+{
+}
+
+void Q3DMaps::initialize()
+{
+ // Initialize shaders
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadow"));
+ // Init the depth buffer (for shadows)
+ d_ptr->initDepthBuffer();
+ } else {
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragmentColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexTexture"),
+ QStringLiteral(":/shaders/fragmentTexture"));
+ }
+ d_ptr->initLabelShaders(QStringLiteral(":/shaders/vertexLabel"),
+ QStringLiteral(":/shaders/fragmentLabel"));
+
+ // Init depth shader (for shadows). Init in any case, easier to handle shadow activation if done via api.
+ d_ptr->initDepthShader();
+
+ // Init selection shader
+ d_ptr->initSelectionShader();
+
+ // Init the selection buffer
+ d_ptr->initSelectionBuffer();
+
+ // Load default mesh
+ d_ptr->loadBarMesh();
+
+ // Load background mesh
+ d_ptr->loadBackgroundMesh();
+
+ // Load grid line mesh
+ d_ptr->loadGridLineMesh();
+
+ // Load label mesh
+ d_ptr->loadLabelMesh();
+
+ // Set OpenGL features
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+ glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+
+ // Set initial camera position
+ // X must be 0 for rotation to work - we can use "setCameraRotation" for setting it later
+ CameraHelper::setDefaultCameraOrientation(QVector3D(0.0f, 0.0f, 1.0f + 2.9f * zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+
+ // Adjust to default rotation
+ setCameraPosition(d_ptr->m_horizontalRotation, d_ptr->m_verticalRotation, d_ptr->m_zoomLevel);
+
+ // Set view port
+ glViewport(0, 0, width(), height());
+
+ // Set initialized -flag
+ d_ptr->m_isInitialized = true;
+
+ // Update default light position
+#ifndef USE_WIDER_SHADOWS
+ distanceMod = 1.0f;
+#endif
+}
+
+void Q3DMaps::render()
+{
+ if (!d_ptr->m_isInitialized)
+ return;
+
+#ifdef DISPLAY_RENDER_SPEED
+ // For speed computation
+ static bool firstRender = true;
+ static QTime lastTime;
+ static GLint nbFrames = 0;
+ if (firstRender) {
+ lastTime.start();
+ firstRender = false;
+ }
+
+ // Measure speed (as milliseconds per frame)
+ nbFrames++;
+ if (lastTime.elapsed() >= 1000) { // print only if last measurement was more than 1s ago
+ qDebug() << qreal(lastTime.elapsed()) / qreal(nbFrames) << "ms/frame (=" << qreal(nbFrames) << "fps)";
+ nbFrames = 0;
+ lastTime.restart();
+ }
+#endif
+
+ // Draw scene
+ drawScene();
+}
+
+void Q3DMaps::drawScene()
+{
+ // Set clear color
+ QVector3D clearColor = Utils::vectorFromColor(d_ptr->m_theme->m_windowColor);
+ glClearColor(clearColor.x(), clearColor.y(), clearColor.z(), 1.0f);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ static QVector3D selection = QVector3D(0, 0, 0);
+
+ // Specify viewport
+ glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(),
+ d_ptr->m_sceneViewPort.width(), d_ptr->m_sceneViewPort.height());
+
+ // Set up projection matrix
+ QMatrix4x4 projectionMatrix;
+ projectionMatrix.perspective(45.0f, (GLfloat)d_ptr->m_sceneViewPort.width()
+ / (GLfloat)d_ptr->m_sceneViewPort.height(), 0.1f, 100.0f);
+
+ // Calculate view matrix
+ QMatrix4x4 viewMatrix = CameraHelper::calculateViewMatrix(d_ptr->m_mousePos,
+ d_ptr->m_zoomLevel
+ * d_ptr->m_zoomAdjustment,
+ d_ptr->m_sceneViewPort.width(),
+ d_ptr->m_sceneViewPort.height());
+
+ // Get light position (rotate light with camera, a bit above it (as set in defaultLightPos))
+ QVector3D lightPos = CameraHelper::calculateLightPosition(defaultLightPos, 0.0f, distanceMod);
+
+ // Map adjustment direction to model matrix scaling
+ GLfloat heightMultiplier = 0.0f;
+ GLfloat widthMultiplier = 0.0f;
+ GLfloat depthMultiplier = 0.0f;
+ GLfloat heightScaler = 0.0f;
+ GLfloat widthScaler = 0.0f;
+ GLfloat depthScaler = 0.0f;
+ switch (d_ptr->m_adjustDirection) {
+ case AdjustHeight:
+ widthMultiplier = 0.0f;
+ heightMultiplier = 1.0f;
+ depthMultiplier = 0.0f;
+ widthScaler = d_ptr->m_barThickness.x() / d_ptr->m_scaleFactor;
+ heightScaler = 0.0f;
+ depthScaler = d_ptr->m_barThickness.z() / d_ptr->m_scaleFactor;
+ break;
+ case AdjustWidth:
+ widthMultiplier = 1.0f;
+ heightMultiplier = 0.0f;
+ depthMultiplier = 0.0f;
+ widthScaler = 0.0f;
+ heightScaler = d_ptr->m_barThickness.y() / d_ptr->m_scaleFactor;
+ depthScaler = d_ptr->m_barThickness.z() / d_ptr->m_scaleFactor;
+ break;
+ case AdjustDepth:
+ widthMultiplier = 0.0f;
+ heightMultiplier = 0.0f;
+ depthMultiplier = 1.0f;
+ widthScaler = d_ptr->m_barThickness.x() / d_ptr->m_scaleFactor;
+ heightScaler = d_ptr->m_barThickness.y() / d_ptr->m_scaleFactor;
+ depthScaler = 0.0f;
+ break;
+ case AdjustRadius:
+ widthMultiplier = 1.0f;
+ heightMultiplier = 0.0f;
+ depthMultiplier = 1.0f;
+ widthScaler = 0.0f;
+ heightScaler = d_ptr->m_barThickness.y() / d_ptr->m_scaleFactor;
+ depthScaler = 0.0f;
+ break;
+ case AdjustAll:
+ widthMultiplier = 1.0f;
+ heightMultiplier = 1.0f;
+ depthMultiplier = 1.0f;
+ widthScaler = 0.0f;
+ heightScaler = 0.0f;
+ depthScaler = 0.0f;
+ break;
+ }
+
+ // Introduce regardless of shadow quality to simplify logic
+ QMatrix4x4 depthViewMatrix;
+ QMatrix4x4 depthProjectionMatrix;
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Render scene into a depth texture for using with shadow mapping
+ // Bind depth shader
+ d_ptr->m_depthShader->bind();
+
+ // Set viewport for depth map rendering. Must match texture size. Larger values give smoother shadows.
+ glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(),
+ d_ptr->m_sceneViewPort.width() * d_ptr->m_shadowQuality,
+ d_ptr->m_sceneViewPort.height() * d_ptr->m_shadowQuality);
+
+ // Enable drawing to framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, d_ptr->m_depthFrameBuffer);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ // Set front face culling to reduce self-shadowing issues
+ glCullFace(GL_FRONT);
+
+ // Get the depth view matrix
+ // It may be possible to hack lightPos here if we want to make some tweaks to shadow
+ depthViewMatrix.lookAt(lightPos, QVector3D(0.0f, -d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ // TODO: Why does depthViewMatrix.column(3).y() goes to zero when we're directly above? That causes the scene to be not drawn from above -> must be fixed
+ //qDebug() << lightPos << depthViewMatrix << depthViewMatrix.column(3);
+ // Set the depth projection matrix
+#ifdef USE_WIDER_SHADOWS
+ // Use this for a bit exaggerated shadows
+ depthProjectionMatrix.perspective(60.0f, (GLfloat)d_ptr->m_sceneViewPort.width()
+ / (GLfloat)d_ptr->m_sceneViewPort.height(), 3.0f, 100.0f);
+#else
+ // Use these for normal shadows, with the light further away
+ depthProjectionMatrix = projectionMatrix;
+#endif
+#if 0
+ // Draw background to depth buffer (You don't want to do this, except maybe for debugging purposes)
+ if (d_ptr->m_backgroundObj) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(0.0f, -d_ptr->m_yAdjustment, zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_areaSize.width() / d_ptr->m_scaleFactor,
+ 1.0f,
+ d_ptr->m_areaSize.height() / d_ptr->m_scaleFactor));
+ modelMatrix.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
+
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ d_ptr->m_depthShader->setUniformValue(d_ptr->m_depthShader->MVP(), MVPMatrix);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(d_ptr->m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_backgroundObj->vertexBuf());
+ glVertexAttribPointer(d_ptr->m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_backgroundObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, d_ptr->m_backgroundObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(d_ptr->m_depthShader->posAtt());
+ }
+#endif
+ // Draw bars to depth buffer
+ for (int bar = 0; bar < d_ptr->m_data->d_ptr->row().size(); bar++) {
+ QDataItem *item = d_ptr->m_data->d_ptr->getItem(bar);
+ if (!item)
+ continue;
+
+ GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer;
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(item->d_ptr->translation().x(),
+ heightMultiplier * barHeight + heightScaler
+ - d_ptr->m_yAdjustment,
+ item->d_ptr->translation().z());
+ modelMatrix.scale(QVector3D(widthMultiplier * barHeight + widthScaler,
+ heightMultiplier * barHeight + heightScaler,
+ depthMultiplier * barHeight + depthScaler));
+
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ d_ptr->m_depthShader->setUniformValue(d_ptr->m_depthShader->MVP(), MVPMatrix);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(d_ptr->m_depthShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf());
+ glVertexAttribPointer(d_ptr->m_depthShader->posAtt(), 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(), GL_UNSIGNED_SHORT, (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(d_ptr->m_depthShader->posAtt());
+ }
+
+ // Disable drawing to framebuffer (= enable drawing to screen)
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // Reset culling to normal
+ glCullFace(GL_BACK);
+
+ // Release depth shader
+ d_ptr->m_depthShader->release();
+
+ // Revert to original viewport
+ glViewport(d_ptr->m_sceneViewPort.x(), d_ptr->m_sceneViewPort.y(),
+ d_ptr->m_sceneViewPort.width(), d_ptr->m_sceneViewPort.height());
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ // You'll also have to comment out GL_COMPARE_R_TO_TEXTURE -line in texturehelper (if using it)
+ d_ptr->m_labelShader->bind();
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.5f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ d_ptr->m_labelShader->setUniformValue(d_ptr->m_labelShader->MVP(), MVPMatrix);
+ d_ptr->m_drawer->drawObject(d_ptr->m_labelShader, d_ptr->m_labelObj,
+ d_ptr->m_depthTexture);
+ glDisable(GL_TEXTURE_2D);
+ d_ptr->m_labelShader->release();
+#endif
+ }
+#if 1
+ // Skip selection mode drawing if we're zoomed or have no selection mode
+ if (!d_ptr->m_zoomActivated && d_ptr->m_selectionMode > ModeNone) {
+ // Bind selection shader
+ d_ptr->m_selectionShader->bind();
+
+ // Draw bars to selection buffer
+ glBindFramebuffer(GL_FRAMEBUFFER, d_ptr->m_selectionFrameBuffer);
+ glEnable(GL_DEPTH_TEST); // Needed, otherwise the depth render buffer is not used
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color to black
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Needed for clearing the frame buffer
+ glDisable(GL_DITHER); // disable dithering, it may affect colors if enabled
+ for (int bar = 0; bar < d_ptr->m_data->d_ptr->row().size(); bar++) {
+ QDataItem *item = d_ptr->m_data->d_ptr->getItem(bar);
+ if (!item)
+ continue;
+
+ GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer;
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+
+ modelMatrix.translate(item->d_ptr->translation().x(),
+ heightMultiplier * barHeight + heightScaler
+ - d_ptr->m_yAdjustment,
+ item->d_ptr->translation().z());
+ modelMatrix.scale(QVector3D(widthMultiplier * barHeight + widthScaler,
+ heightMultiplier * barHeight + heightScaler,
+ depthMultiplier * barHeight + depthScaler));
+
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+
+ // add +2 to avoid black
+ QVector3D barColor = QVector3D((GLdouble)(bar + 2)
+ / (GLdouble)(d_ptr->m_data->d_ptr->row().size() + 2),
+ (GLdouble)(bar + 2)
+ / (GLdouble)(d_ptr->m_data->d_ptr->row().size() + 2),
+ 0.0);
+
+ d_ptr->m_selectionShader->setUniformValue(d_ptr->m_selectionShader->MVP(),
+ MVPMatrix);
+ d_ptr->m_selectionShader->setUniformValue(d_ptr->m_selectionShader->color(),
+ barColor);
+
+ // 1st attribute buffer : vertices
+ glEnableVertexAttribArray(d_ptr->m_selectionShader->posAtt());
+ glBindBuffer(GL_ARRAY_BUFFER, d_ptr->m_barObj->vertexBuf());
+ glVertexAttribPointer(d_ptr->m_selectionShader->posAtt(),
+ 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+
+ // Index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, d_ptr->m_barObj->elementBuf());
+
+ // Draw the triangles
+ glDrawElements(GL_TRIANGLES, d_ptr->m_barObj->indexCount(), GL_UNSIGNED_SHORT,
+ (void *)0);
+
+ // Free buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(d_ptr->m_selectionShader->posAtt());
+ }
+ glEnable(GL_DITHER);
+
+ // Read color under cursor
+ if (Q3DMapsPrivate::MouseOnScene == d_ptr->m_mousePressed)
+ selection = Utils::getSelection(d_ptr->m_mousePos, height());
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // Release selection shader
+ d_ptr->m_selectionShader->release();
+
+#if 0 // Use this if you want to see what is being drawn to the framebuffer
+ d_ptr->m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 viewmatrix;
+ viewmatrix.lookAt(QVector3D(0.0f, 0.0f, 2.0f + zComp),
+ QVector3D(0.0f, 0.0f, zComp),
+ QVector3D(0.0f, 1.0f, 0.0f));
+ modelMatrix.translate(0.0, 0.0, zComp);
+ QMatrix4x4 MVPMatrix = projectionMatrix * viewmatrix * modelMatrix;
+ d_ptr->m_labelShader->setUniformValue(d_ptr->m_labelShader->MVP(), MVPMatrix);
+ d_ptr->m_drawer->drawObject(d_ptr->m_labelShader, d_ptr->m_labelObj,
+ d_ptr->m_selectionTexture);
+ glDisable(GL_TEXTURE_2D);
+ d_ptr->m_labelShader->release();
+#endif
+ }
+#if 1
+ // Bind bar shader
+ d_ptr->m_barShader->bind();
+
+ // Enable texture
+ glEnable(GL_TEXTURE_2D);
+
+ // Draw bars
+ // TODO: Handle zoom by camera transformations
+ //if (!d_ptr->m_zoomActivated)
+
+ bool barSelectionFound = false;
+ for (int bar = 0; bar < d_ptr->m_data->d_ptr->row().size(); bar++) {
+ QDataItem *item = d_ptr->m_data->d_ptr->getItem(bar);
+ if (!item)
+ continue;
+
+ GLfloat barHeight = item->d_ptr->value() / d_ptr->m_heightNormalizer;
+
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(item->d_ptr->translation().x(),
+ heightMultiplier * barHeight + heightScaler - d_ptr->m_yAdjustment,
+ item->d_ptr->translation().z());
+ modelMatrix.scale(QVector3D(widthMultiplier * barHeight + widthScaler,
+ heightMultiplier * barHeight + heightScaler,
+ depthMultiplier * barHeight + depthScaler));
+ itModelMatrix.scale(QVector3D(widthMultiplier * barHeight + widthScaler,
+ heightMultiplier * barHeight + heightScaler,
+ depthMultiplier * barHeight + depthScaler));
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ QVector3D baseColor = Utils::vectorFromColor(d_ptr->m_theme->m_baseColor);
+ QVector3D heightColor = Utils::vectorFromColor(d_ptr->m_theme->m_heightColor)
+ * barHeight;
+
+ QVector3D barColor = baseColor + heightColor;
+
+ GLfloat lightStrength = d_ptr->m_theme->m_lightStrength;
+ if (d_ptr->m_selectionMode > ModeNone) {
+ Q3DMapsPrivate::SelectionType selectionType = d_ptr->isSelected(bar, selection);
+ switch (selectionType) {
+ case Q3DMapsPrivate::SelectionBar: {
+ barColor = Utils::vectorFromColor(d_ptr->m_theme->m_highlightBarColor);
+ lightStrength = d_ptr->m_theme->m_highlightLightStrength;
+ // Insert data to QDataItem. We have no ownership, don't delete the previous one
+ if (!d_ptr->m_zoomActivated) {
+ d_ptr->m_selectedBar = item;
+ barSelectionFound = true;
+ }
+ break;
+ }
+ case Q3DMapsPrivate::SelectionNone: {
+ // Current bar is not selected, nor on a row or column
+ // do nothing
+ break;
+ }
+ default: {
+ // Unsupported selection mode
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ if (barHeight != 0) {
+ // Set shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightP(), lightPos);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->view(), viewMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->model(), modelMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->MVP(), MVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->color(), barColor);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->ambientS(),
+ d_ptr->m_theme->m_ambientStrength);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(),
+ lightStrength / 10.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj,
+ 0, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_barShader->setUniformValue(d_ptr->m_barShader->lightS(), lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_barShader, d_ptr->m_barObj);
+ }
+ }
+ }
+
+ // Release bar shader
+ d_ptr->m_barShader->release();
+#if 1
+ // Bind background shader
+ d_ptr->m_backgroundShader->bind();
+
+ // Draw background
+ if (d_ptr->m_backgroundObj) {
+ QMatrix4x4 modelMatrix;
+ QMatrix4x4 MVPMatrix;
+ QMatrix4x4 depthMVPMatrix;
+ QMatrix4x4 itModelMatrix;
+
+ modelMatrix.translate(0.0f, -d_ptr->m_yAdjustment, zComp);
+ modelMatrix.scale(QVector3D(d_ptr->m_areaSize.width() / d_ptr->m_scaleFactor,
+ 1.0f,
+ d_ptr->m_areaSize.height() / d_ptr->m_scaleFactor));
+ modelMatrix.rotate(-90.0f, 1.0f, 0.0f, 0.0f);
+ itModelMatrix.scale(QVector3D(d_ptr->m_areaSize.width() / d_ptr->m_scaleFactor,
+ 1.0f,
+ d_ptr->m_areaSize.height() / d_ptr->m_scaleFactor));
+
+#ifdef SHOW_DEPTH_TEXTURE_SCENE
+ MVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+#else
+ MVPMatrix = projectionMatrix * viewMatrix * modelMatrix;
+#endif
+ depthMVPMatrix = depthProjectionMatrix * depthViewMatrix * modelMatrix;
+
+ // Set shader bindings
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightP(), lightPos);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->view(), viewMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->model(), modelMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->nModel(),
+ itModelMatrix.inverted().transposed());
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->MVP(), MVPMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->ambientS(),
+ d_ptr->m_theme->m_ambientStrength * 3.0f);
+
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Set shadow shader bindings
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->shadowQ(),
+ d_ptr->m_shadowQualityToShader);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->depth(),
+ depthMVPMatrix);
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightS(),
+ d_ptr->m_theme->m_lightStrength / 25.0f);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj,
+ d_ptr->m_bgrTexture, d_ptr->m_depthTexture);
+ } else {
+ // Set shadowless shader bindings
+ d_ptr->m_backgroundShader->setUniformValue(d_ptr->m_backgroundShader->lightS(),
+ d_ptr->m_theme->m_lightStrength);
+
+ // Draw the object
+ d_ptr->m_drawer->drawObject(d_ptr->m_backgroundShader, d_ptr->m_backgroundObj,
+ d_ptr->m_bgrTexture);
+ }
+ }
+
+ // Disable textures
+ glDisable(GL_TEXTURE_2D);
+
+ // Release background shader
+ d_ptr->m_backgroundShader->release();
+#endif
+
+ // Handle zoom activation and label drawing
+ if (!barSelectionFound) {
+ // We have no ownership, don't delete. Just NULL the pointer.
+ d_ptr->m_selectedBar = NULL;
+ //if (d_ptr->m_zoomActivated && Q3DMapsPrivate::MouseOnOverview == d_ptr->m_mousePressed) {
+ //d_ptr->m_sceneViewPort = QRect(0, 0, width(), height());
+ //d_ptr->m_zoomActivated = false;
+ //}
+ } /*else if (d_ptr->m_selectionMode >= ModeZoomRow
+ && Q3DMapsPrivate::MouseOnScene == d_ptr->m_mousePressed) {
+ // Activate zoom mode
+ d_ptr->m_zoomActivated = true;
+ d_ptr->m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5);
+
+ // Create label textures
+ for (int col = 0; col < d_ptr->m_zoomSelection->d_ptr->row().size(); col++) {
+ QDataItem *item = d_ptr->m_zoomSelection->d_ptr->getItem(col);
+ d_ptr->m_drawer->generateLabelTexture(item);
+ }
+ }*/ else {
+ // Print value of selected bar
+ static QDataItem *prevItem = d_ptr->m_selectedBar;
+ d_ptr->m_labelShader->bind();
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+#ifndef DISPLAY_FULL_DATA_ON_SELECTION
+ // Draw just the value string of the selected bar
+ if (prevItem != d_ptr->m_selectedBar || d_ptr->m_updateLabels) {
+ d_ptr->m_drawer->generateLabelTexture(d_ptr->m_selectedBar);
+ prevItem = d_ptr->m_selectedBar;
+ }
+
+ d_ptr->m_drawer->drawLabel(*d_ptr->m_selectedBar, d_ptr->m_selectedBar->d_ptr->label(),
+ viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true);
+#else
+ static bool firstSelection = true;
+ // Draw the value string followed by row label and column label
+ LabelItem labelItem = d_ptr->m_selectedBar->d_ptr->selectionLabel();
+ if (firstSelection || prevItem != d_ptr->m_selectedBar || d_ptr->m_updateLabels) {
+ QString labelText = d_ptr->m_selectedBar->d_ptr->valueStr();
+ // if ((d_ptr->m_data->d_ptr->columnLabels().size()
+ // > d_ptr->m_selectedBar->d_ptr->position().y())
+ // && (d_ptr->m_data->d_ptr->rowLabels().size()
+ // > d_ptr->m_selectedBar->d_ptr->position().x())) {
+ // labelText.append(QStringLiteral(" ("));
+ // labelText.append(d_ptr->m_data->d_ptr->rowLabels().at(
+ // d_ptr->m_selectedBar->d_ptr->position().x()));
+ // labelText.append(QStringLiteral(", "));
+ // labelText.append(d_ptr->m_data->d_ptr->columnLabels().at(
+ // d_ptr->m_selectedBar->d_ptr->position().y()));
+ // labelText.append(QStringLiteral(")"));
+ // //qDebug() << labelText;
+ // }
+ d_ptr->m_drawer->generateLabelItem(&labelItem, labelText);
+ d_ptr->m_selectedBar->d_ptr->setSelectionLabel(labelItem);
+ prevItem = d_ptr->m_selectedBar;
+ firstSelection = false;
+ }
+
+ d_ptr->m_drawer->drawLabel(*d_ptr->m_selectedBar, labelItem, viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(0.0f, 0.0f, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true, false);
+#endif
+ glDisable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone)
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+
+ // Release label shader
+ d_ptr->m_labelShader->release();
+
+ // Reset label update flag; they should have been updated when we get here
+ d_ptr->m_updateLabels = false;
+ }
+#if 0
+ // TODO: Calculations done temporarily here. When optimizing, move to after data set addition? Keep drawing of the labels here.
+ // Bind label shader
+ d_ptr->m_labelShader->bind();
+
+ glEnable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ // Calculate the positions for row and column labels and store them into QDataItems (and QDataRows?)
+ for (int row = 0; row != d_ptr->m_sampleCount.second; row += 1) {
+ // Go through all rows and get position of max+1 or min-1 column, depending on x flip
+ // We need only positions for them, labels have already been generated at QDataSet. Just add LabelItems
+ rowPos = (row + 1) * (d_ptr->m_barSpacing.height());
+ barPos = 0;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 0.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignRight;
+ if (d_ptr->m_zFlipped)
+ rotLabelY = 180.0f;
+ if (d_ptr->m_xFlipped) {
+ barPos = (d_ptr->m_sampleCount.first + 1) * (d_ptr->m_barSpacing.width());
+ alignment = Qt::AlignLeft;
+ }
+ QVector3D labelPos = QVector3D((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ -d_ptr->m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor
+ + zComp);
+
+ // TODO: Try it; draw the label here
+
+ // Create a data item
+ QDataItem *label = new QDataItem();
+ label->d_ptr->setTranslation(labelPos);
+ if (d_ptr->m_data->d_ptr->rowLabelItems().size() > row) {
+ label->d_ptr->setLabel(d_ptr->m_data->d_ptr->rowLabelItems().at(
+ d_ptr->m_data->d_ptr->rowLabelItems().size() - row - 1));
+ }
+
+ //qDebug() << "labelPos, row" << row + 1 << ":" << labelPos << d_ptr->m_dataSet->d_ptr->rowLabels().at(row);
+
+ d_ptr->m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true, true, LabelMid, alignment);
+
+ delete label;
+ }
+ for (int bar = 0; bar != d_ptr->m_sampleCount.first; bar += 1) {
+ // Go through all columns and get position of max+1 or min-1 row, depending on z flip
+ // We need only positions for them, labels have already been generated at QDataSet. Just add LabelItems
+ barPos = (bar + 1) * (d_ptr->m_barSpacing.width());
+ rowPos = 0;
+ GLfloat rotLabelX = -90.0f;
+ GLfloat rotLabelY = 90.0f;
+ Qt::AlignmentFlag alignment = Qt::AlignLeft;
+ if (d_ptr->m_xFlipped)
+ rotLabelY = -90.0f;
+ if (d_ptr->m_zFlipped) {
+ rowPos = (d_ptr->m_sampleCount.second + 1) * (d_ptr->m_barSpacing.height());
+ alignment = Qt::AlignRight;
+ }
+ QVector3D labelPos = QVector3D((d_ptr->m_rowWidth - barPos) / d_ptr->m_scaleFactor,
+ -d_ptr->m_yAdjustment + 0.005f, // raise a bit over background to avoid depth "glimmering"
+ (d_ptr->m_columnDepth - rowPos) / d_ptr->m_scaleFactor
+ + zComp);
+
+ // TODO: Try it; draw the label here
+
+ // Create a data item
+ QDataItem *label = new QDataItem();
+ label->d_ptr->setTranslation(labelPos);
+ if (d_ptr->m_data->d_ptr->columnLabelItems().size() > bar) {
+ label->d_ptr->setLabel(d_ptr->m_data->d_ptr->columnLabelItems().at(
+ d_ptr->m_data->d_ptr->columnLabelItems().size()
+ - bar - 1));
+ }
+
+ //qDebug() << "labelPos, col" << bar + 1 << ":" << labelPos << d_ptr->m_dataSet->d_ptr->columnLabels().at(bar);
+
+ d_ptr->m_drawer->drawLabel(*label, label->d_ptr->label(), viewMatrix, projectionMatrix,
+ QVector3D(0.0f, d_ptr->m_yAdjustment, zComp),
+ QVector3D(rotLabelX, rotLabelY, 0.0f), d_ptr->m_heightNormalizer,
+ d_ptr->m_selectionMode, d_ptr->m_labelShader,
+ d_ptr->m_labelObj, true, true, LabelMid, alignment);
+
+ delete label;
+ }
+ glDisable(GL_TEXTURE_2D);
+ if (d_ptr->m_labelTransparency > TransparencyNone)
+ glDisable(GL_BLEND);
+
+ // Release label shader
+ d_ptr->m_labelShader->release();
+#endif
+#endif
+#endif
+}
+
+void Q3DMaps::mousePressEvent(QMouseEvent *event)
+{
+ if (Qt::LeftButton == event->button()) {
+ if (d_ptr->m_zoomActivated) {
+ //qDebug() << event->pos().x() << event->pos().y() << d_ptr->m_sceneViewPort << d_ptr->m_zoomViewPort;
+ if (event->pos().x() <= d_ptr->m_sceneViewPort.width()
+ && event->pos().y() <= d_ptr->m_sceneViewPort.height()) {
+ d_ptr->m_mousePressed = Q3DMapsPrivate::MouseOnOverview;
+ //qDebug() << "Mouse pressed on overview";
+ } else {
+ d_ptr->m_mousePressed = Q3DMapsPrivate::MouseOnZoom;
+ //qDebug() << "Mouse pressed on zoom";
+ }
+ } else {
+ d_ptr->m_mousePressed = Q3DMapsPrivate::MouseOnScene;
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ d_ptr->m_mousePos = event->pos();
+ //qDebug() << "Mouse pressed on scene";
+ }
+ } else if (Qt::MiddleButton == event->button()) {
+ // reset rotations
+ d_ptr->m_mousePos = QPoint(0, 0);
+ } else if (Qt::RightButton == event->button()) {
+ d_ptr->m_mousePressed = Q3DMapsPrivate::MouseRotating;
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ d_ptr->m_mousePos = event->pos();
+ }
+ CameraHelper::updateMousePos(d_ptr->m_mousePos);
+}
+
+void Q3DMaps::mouseReleaseEvent(QMouseEvent *event)
+{
+ //qDebug() << "mouse button released" << event->button();
+ if (Q3DMapsPrivate::MouseRotating == d_ptr->m_mousePressed) {
+ // update mouse positions to prevent jumping when releasing or repressing a button
+ d_ptr->m_mousePos = event->pos();
+ CameraHelper::updateMousePos(event->pos());
+ }
+ d_ptr->m_mousePressed = Q3DMapsPrivate::MouseNone;
+}
+
+void Q3DMaps::mouseMoveEvent(QMouseEvent *event)
+{
+ if (Q3DMapsPrivate::MouseRotating == d_ptr->m_mousePressed) {
+ //qDebug() << "mouse moved while pressed" << event->pos();
+ d_ptr->m_mousePos = event->pos();
+ }
+#if 0
+ // TODO: Testi - laske kursorin sijainti scenessä
+ QPointF mouse3D((2.0f * event->pos().x() - width()) / height(),
+ 1.0f - (2.0f * event->pos().y()) / height());
+ //qDebug() << "mouse position in scene" << mouse3D;
+
+ // TODO: Testi laske focal point
+ GLfloat focalPoint = tan(45.0f / 2.0f);
+
+ // TODO: Testi - laske viewmatriisin kerroin
+ QVector3D worldRay = QVector3D(0.0f, 0.0f, 0.0f)
+ - QVector3D(mouse3D.x(), mouse3D.y(), -focalPoint);
+ //qDebug() << "worldRay" << worldRay;
+ // multiply viewmatrix with this to get something?
+#endif
+}
+
+void Q3DMaps::wheelEvent(QWheelEvent *event)
+{
+ if (d_ptr->m_zoomLevel > 100)
+ d_ptr->m_zoomLevel += event->angleDelta().y() / 12;
+ else if (d_ptr->m_zoomLevel > 50)
+ d_ptr->m_zoomLevel += event->angleDelta().y() / 60;
+ else
+ d_ptr->m_zoomLevel += event->angleDelta().y() / 120;
+ if (d_ptr->m_zoomLevel > 500)
+ d_ptr->m_zoomLevel = 500;
+ else if (d_ptr->m_zoomLevel < 10)
+ d_ptr->m_zoomLevel = 10;
+}
+
+void Q3DMaps::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event);
+
+ // Set view port
+ if (d_ptr->m_zoomActivated)
+ d_ptr->m_sceneViewPort = QRect(0, height() - height() / 5, width() / 5, height() / 5);
+ else
+ d_ptr->m_sceneViewPort = QRect(0, 0, width(), height());
+ d_ptr->m_zoomViewPort = QRect(0, 0, width(), height());
+
+ // Calculate zoom level based on aspect ratio
+ GLfloat div;
+ GLfloat zoomAdjustment;
+ div = qMin(width(), height());
+ zoomAdjustment = defaultRatio * ((width() / div) / (height() / div));
+ //qDebug() << "zoom adjustment" << zoomAdjustment;
+ d_ptr->m_zoomAdjustment = qMin(zoomAdjustment, 1.0f); // clamp to 1.0f
+
+ // Re-init selection buffer
+ d_ptr->initSelectionBuffer();
+
+ // Re-init depth buffer
+ d_ptr->initDepthBuffer();
+}
+
+void Q3DMaps::setBarSpecs(const QVector3D &thickness, AdjustmentDirection direction)
+{
+ d_ptr->m_barThickness = thickness;
+ d_ptr->m_adjustDirection = direction;
+}
+
+void Q3DMaps::setBarType(BarStyle style, bool smooth)
+{
+ if (style == Bars) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/barSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/bar");
+ } else if (style == Pyramids) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/pyramidSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/pyramid");
+ } else if (style == Cones) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/coneSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cone");
+ } else if (style == Cylinders) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cylinderSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/cylinder");
+ } else if (style == Spheres) {
+ if (smooth)
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/sphereSmooth");
+ else
+ d_ptr->m_objFile = QStringLiteral(":/defaultMeshes/sphere");
+ }
+ // Reload mesh data
+ if (d_ptr->m_isInitialized)
+ d_ptr->loadBarMesh();
+}
+
+void Q3DMaps::setMeshFileName(const QString &objFileName)
+{
+ d_ptr->m_objFile = objFileName;
+}
+
+void Q3DMaps::setCameraPreset(CameraPreset preset)
+{
+ CameraHelper::setCameraPreset(preset);
+}
+
+void Q3DMaps::setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance)
+{
+ d_ptr->m_horizontalRotation = qBound(-180.0f, horizontal, 180.0f);
+ d_ptr->m_verticalRotation = qBound(0.0f, vertical, 90.0f);
+ d_ptr->m_zoomLevel = qBound(10, distance, 500);
+ CameraHelper::setCameraRotation(QPointF(d_ptr->m_horizontalRotation,
+ d_ptr->m_verticalRotation));
+ //qDebug() << "camera rotation set to" << d_ptr->m_horizontalRotation << d_ptr->m_verticalRotation;
+}
+
+void Q3DMaps::setTheme(ColorTheme theme)
+{
+ d_ptr->m_theme->useTheme(theme);
+ d_ptr->m_drawer->setTheme(*d_ptr->m_theme);
+ // Re-initialize shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ d_ptr->m_updateLabels = true;
+}
+
+void Q3DMaps::setBarColor(QColor baseColor, QColor heightColor, bool uniform)
+{
+ d_ptr->m_theme->m_baseColor = baseColor;
+ d_ptr->m_theme->m_heightColor = heightColor;
+ if (d_ptr->m_theme->m_uniformColor != uniform) {
+ // Re-initialize shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ }
+ d_ptr->m_theme->m_uniformColor = uniform;
+}
+
+void Q3DMaps::setSelectionMode(SelectionMode mode)
+{
+ d_ptr->m_selectionMode = mode;
+ // Disable zoom if mode changes
+ //d_ptr->m_zoomActivated = false;
+ //d_ptr->m_sceneViewPort = QRect(0, 0, width(), height());
+}
+
+void Q3DMaps::setWindowTitle(const QString &title)
+{
+ setTitle(title);
+}
+
+void Q3DMaps::setFontSize(float fontsize)
+{
+ d_ptr->m_font.setPointSizeF(fontsize);
+ d_ptr->m_drawer->setFont(d_ptr->m_font);
+ d_ptr->m_updateLabels = true;
+}
+
+void Q3DMaps::setFont(const QFont &font)
+{
+ d_ptr->m_font = font;
+ d_ptr->m_drawer->setFont(font);
+ d_ptr->m_updateLabels = true;
+}
+
+void Q3DMaps::setLabelTransparency(LabelTransparency transparency)
+{
+ d_ptr->m_labelTransparency = transparency;
+ d_ptr->m_drawer->setTransparency(transparency);
+ d_ptr->m_updateLabels = true;
+}
+
+void Q3DMaps::setGridEnabled(bool enable)
+{
+ d_ptr->m_gridEnabled = enable;
+}
+
+bool Q3DMaps::addDataItem(QDataItem* dataItem)
+{
+ // Check validity
+ if (!d_ptr->isValid(*dataItem))
+ return false;
+ // Convert position to translation
+ d_ptr->calculateTranslation(dataItem);
+ // Add item
+ d_ptr->m_data->addItem(dataItem);
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_data->d_ptr->limitValues();
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ return true;
+}
+
+bool Q3DMaps::addData(const QVector<QDataItem*> &data)
+{
+ // Convert to QDataRow
+ for (int i = 0; i < data.size(); i++) {
+ QDataItem *item = data.at(i);
+ // Check validity
+ if (!d_ptr->isValid(*item)) {
+ return false;
+ } else {
+ // Convert position to translation
+ d_ptr->calculateTranslation(item);
+ // Add item
+ d_ptr->m_data->addItem(item);
+ }
+ }
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_data->d_ptr->limitValues();
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ return true;
+}
+
+bool Q3DMaps::addData(const QDataRow &dataRow)
+{
+ for (int itemIdx = 0; itemIdx < dataRow.d_ptr->row().size(); itemIdx++) {
+ QDataItem *item = dataRow.d_ptr->getItem(itemIdx);
+ // Check validity
+ if (!d_ptr->isValid(*item)) {
+ return false;
+ } else {
+ // Convert position to translation
+ d_ptr->calculateTranslation(item);
+ // Add item
+ d_ptr->m_data->addItem(item);
+ }
+ }
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_data->d_ptr->limitValues();
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ return true;
+}
+
+bool Q3DMaps::setData(const QVector<QDataItem*> &dataRow)
+{
+ // Delete previous data
+ delete d_ptr->m_data;
+ // Convert to QDataRow
+ d_ptr->m_data = new QDataRow();
+ for (int i = 0; i < dataRow.size(); i++) {
+ QDataItem *item = dataRow.at(i);
+ // Check validity
+ if (!d_ptr->isValid(*item)) {
+ return false;
+ } else {
+ // Convert position to translation
+ d_ptr->calculateTranslation(item);
+ // Add item
+ d_ptr->m_data->addItem(item);
+ }
+ }
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_data->d_ptr->limitValues();
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ return true;
+}
+
+bool Q3DMaps::setData(QDataRow *dataRow)
+{
+ // Check validity
+ for (int i = 0; i < dataRow->d_ptr->row().size(); i++) {
+ if (!d_ptr->isValid(*dataRow->d_ptr->row().at(i)))
+ return false;
+ else
+ d_ptr->calculateTranslation(dataRow->d_ptr->row()[i]);
+ }
+ // Delete previous data
+ delete d_ptr->m_data;
+ // Set give data as new data
+ d_ptr->m_data = dataRow;
+ // Get the limits
+ QPair<GLfloat, GLfloat> limits = d_ptr->m_data->d_ptr->limitValues();
+ d_ptr->m_heightNormalizer = (GLfloat)qMax(qFabs(limits.second), qFabs(limits.first));
+ d_ptr->calculateHeightAdjustment(limits);
+ return true;
+}
+
+void Q3DMaps::setAreaSpecs(const QRect &areaRect, const QImage &image)
+{
+ d_ptr->calculateSceneScalingFactors(areaRect);
+ setImage(image);
+}
+
+void Q3DMaps::setImage(const QImage &image)
+{
+ if (d_ptr->m_bgrTexture)
+ glDeleteTextures(1, &d_ptr->m_bgrTexture);
+ d_ptr->m_bgrTexture = d_ptr->m_textureHelper->create2DTexture(image, true, true);
+}
+
+void Q3DMaps::setShadowQuality(ShadowQuality quality)
+{
+ d_ptr->m_shadowQuality = quality;
+ switch (quality) {
+ case ShadowLow:
+ //qDebug() << "ShadowLow";
+ d_ptr->m_shadowQualityToShader = 33.3f;
+ break;
+ case ShadowMedium:
+ //qDebug() << "ShadowMedium";
+ d_ptr->m_shadowQualityToShader = 100.0f;
+ break;
+ case ShadowHigh:
+ //qDebug() << "ShadowHigh";
+ d_ptr->m_shadowQualityToShader = 200.0f;
+ break;
+ default:
+ d_ptr->m_shadowQualityToShader = 0.0f;
+ break;
+ }
+ if (d_ptr->m_shadowQuality > ShadowNone) {
+ // Re-init depth buffer
+ d_ptr->initDepthBuffer();
+ // Re-init shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTexColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadowNoTex"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexShadow"),
+ QStringLiteral(":/shaders/fragmentShadow"));
+ } else {
+ // Re-init shaders
+ if (!d_ptr->m_theme->m_uniformColor) {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragmentColorOnY"));
+ } else {
+ d_ptr->initShaders(QStringLiteral(":/shaders/vertex"),
+ QStringLiteral(":/shaders/fragment"));
+ }
+ d_ptr->initBackgroundShaders(QStringLiteral(":/shaders/vertexTexture"),
+ QStringLiteral(":/shaders/fragmentTexture"));
+ }
+}
+
+Q3DMapsPrivate::Q3DMapsPrivate(Q3DMaps *q)
+ : q_ptr(q),
+ m_paintDevice(0),
+ m_barShader(0),
+ m_depthShader(0),
+ m_selectionShader(0),
+ m_backgroundShader(0),
+ m_labelShader(0),
+ m_barObj(0),
+ m_backgroundObj(0),
+ m_gridLineObj(0),
+ m_labelObj(0),
+ m_objFile(QStringLiteral(":/defaultMeshes/bar")),
+ m_mousePressed(MouseNone),
+ m_mousePos(QPoint(0, 0)),
+ m_zoomLevel(100),
+ m_zoomAdjustment(1.0f),
+ m_horizontalRotation(0.0f),
+ m_verticalRotation(45.0f),
+ m_barThickness(QVector3D(1.0f, 0.0f, 1.0f)),
+ m_heightNormalizer(0.0f),
+ m_yAdjustment(0.0f),
+ m_scaleFactor(1.0f),
+ m_theme(new Theme()),
+ m_isInitialized(false),
+ m_selectionMode(ModeBar),
+ m_selectedBar(0),
+ m_data(new QDataRow()),
+ m_axisLabelX(QStringLiteral("X")),
+ m_axisLabelZ(QStringLiteral("Z")),
+ m_axisLabelY(QStringLiteral("Y")),
+ m_sceneViewPort(0, 0, q->width(), q->height()),
+ m_zoomViewPort(0, 0, q->width(), q->height()),
+ m_zoomActivated(false),
+ m_textureHelper(new TextureHelper()),
+ m_labelTransparency(TransparencyNone),
+ m_font(QFont(QStringLiteral("Arial"))),
+ m_drawer(new Drawer(*m_theme, m_font, m_labelTransparency)),
+ m_bgrTexture(0),
+ m_depthTexture(0),
+ m_selectionTexture(0),
+ m_depthFrameBuffer(0),
+ m_selectionFrameBuffer(0),
+ m_selectionDepthBuffer(0),
+ m_areaSize(QSizeF(1.0f, 1.0f)),
+ m_updateLabels(true),
+ m_gridEnabled(true),
+ m_shadowQuality(ShadowLow),
+ m_shadowQualityToShader(33.3f)
+{
+ //m_data->d_ptr->setDrawer(m_drawer);
+ //QObject::connect(m_drawer, &Drawer::drawerChanged, this, &Q3DMapsPrivate::updateTextures);
+}
+
+Q3DMapsPrivate::~Q3DMapsPrivate()
+{
+ m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer);
+ m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer);
+ m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer);
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+ m_textureHelper->deleteTexture(&m_bgrTexture);
+ delete m_data;
+ delete m_barShader;
+ delete m_selectionShader;
+ delete m_backgroundShader;
+ delete m_barObj;
+ delete m_backgroundObj;
+ delete m_gridLineObj;
+ delete m_textureHelper;
+ delete m_drawer;
+}
+
+void Q3DMapsPrivate::loadBarMesh()
+{
+ if (m_barObj)
+ delete m_barObj;
+ m_barObj = new ObjectHelper(m_objFile);
+ m_barObj->load();
+}
+
+void Q3DMapsPrivate::loadBackgroundMesh()
+{
+ if (m_backgroundObj)
+ delete m_backgroundObj;
+ m_backgroundObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label"));
+ m_backgroundObj->load();
+}
+
+void Q3DMapsPrivate::loadGridLineMesh()
+{
+ if (m_gridLineObj)
+ delete m_gridLineObj;
+ m_gridLineObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/bar"));
+ m_gridLineObj->load();
+}
+
+void Q3DMapsPrivate::loadLabelMesh()
+{
+ if (m_labelObj)
+ delete m_labelObj;
+ m_labelObj = new ObjectHelper(QStringLiteral(":/defaultMeshes/label"));
+ m_labelObj->load();
+}
+
+void Q3DMapsPrivate::initShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_barShader)
+ delete m_barShader;
+ m_barShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader);
+ m_barShader->initialize();
+}
+
+void Q3DMapsPrivate::initSelectionShader()
+{
+ if (m_selectionShader)
+ delete m_selectionShader;
+ m_selectionShader = new ShaderHelper(q_ptr, QStringLiteral(":/shaders/vertexSelection"),
+ QStringLiteral(":/shaders/fragmentSelection"));
+ m_selectionShader->initialize();
+}
+
+void Q3DMapsPrivate::initDepthShader()
+{
+ if (m_depthShader)
+ delete m_depthShader;
+ m_depthShader = new ShaderHelper(q_ptr, QStringLiteral(":/shaders/vertexDepth"),
+ QStringLiteral(":/shaders/fragmentDepth"));
+ m_depthShader->initialize();
+}
+
+void Q3DMapsPrivate::initSelectionBuffer()
+{
+ if (m_selectionTexture) {
+ m_textureHelper->glDeleteFramebuffers(1, &m_selectionFrameBuffer);
+ m_textureHelper->glDeleteRenderbuffers(1, &m_selectionDepthBuffer);
+ m_textureHelper->deleteTexture(&m_selectionTexture);
+ }
+ m_selectionTexture = m_textureHelper->createSelectionTexture(q_ptr->size(),
+ m_selectionFrameBuffer,
+ m_selectionDepthBuffer);
+}
+
+void Q3DMapsPrivate::initDepthBuffer()
+{
+ if (m_depthTexture) {
+ m_textureHelper->glDeleteFramebuffers(1, &m_depthFrameBuffer);
+ m_textureHelper->deleteTexture(&m_depthTexture);
+ }
+ m_depthTexture = m_textureHelper->createDepthTexture(q_ptr->size(), m_depthFrameBuffer,
+ m_shadowQuality);
+}
+
+void Q3DMapsPrivate::initBackgroundShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ if (m_backgroundShader)
+ delete m_backgroundShader;
+ m_backgroundShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader);
+ m_backgroundShader->initialize();
+}
+
+void Q3DMapsPrivate::initLabelShaders(const QString &vertexShader, const QString &fragmentShader)
+{
+ if (m_labelShader)
+ delete m_labelShader;
+ m_labelShader = new ShaderHelper(q_ptr, vertexShader, fragmentShader);
+ // m_labelShader = new ShaderHelper(q_ptr, QStringLiteral(":/shaders/testDepthVert"),
+ // QStringLiteral(":/shaders/testDepthFrag"));
+ m_labelShader->initialize();
+}
+
+void Q3DMapsPrivate::updateTextures()
+{
+ // Drawer has changed; this flag needs to be checked when checking if we need to update labels
+ m_updateLabels = true;
+}
+
+void Q3DMapsPrivate::calculateSceneScalingFactors(const QRect &areaRect)
+{
+ m_areaSize = areaRect.size();
+ // Calculate scaling factor so that we can be sure the whole area fits to positive z space
+ if (zComp > 1.0f)
+ m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height()) / zComp;
+ else
+ m_scaleFactor = qMax(m_areaSize.width(), m_areaSize.height());
+ //qDebug() << "scaleFactor" << m_scaleFactor;
+}
+
+void Q3DMapsPrivate::calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits)
+{
+ // 2.0f = max difference between minimum and maximum value after scaling with m_heightNormalizer
+ m_yAdjustment = 2.0f - ((limits.second - limits.first) / m_heightNormalizer);
+ //qDebug() << m_yAdjustment;
+}
+
+void Q3DMapsPrivate::calculateTranslation(QDataItem *item)
+{
+ // We need to convert position (which is in coordinates), to translation (which has origin in the center and is scaled)
+ // -> move pos(center, center) to trans(0, 0) and pos(0, 0) to trans(left, top)
+ GLfloat xTrans = 2.0f * (item->d_ptr->position().x() - (m_areaSize.width() / 2.0f))
+ / m_scaleFactor;
+ GLfloat zTrans = 2.0f * (item->d_ptr->position().y() - (m_areaSize.height() / 2.0f))
+ / m_scaleFactor;
+ //qDebug() << "x, y" << item->d_ptr->position().x() << item->d_ptr->position().y();
+ item->d_ptr->setTranslation(QVector3D(xTrans, 0.0f, zTrans + zComp));
+ //qDebug() << item->d_ptr->translation();
+}
+
+Q3DMapsPrivate::SelectionType Q3DMapsPrivate::isSelected(GLint bar, const QVector3D &selection)
+{
+ //static QVector3D prevSel = selection; // TODO: For debugging
+ SelectionType isSelectedType = SelectionNone;
+ if (selection == Utils::vectorFromColor(Qt::black))
+ return isSelectedType; // skip window
+ QVector3D current = QVector3D((GLubyte)((GLdouble)(bar + 2)
+ / (GLdouble)(m_data->d_ptr->row().size() + 2)
+ * 255.0 + 0.49), // +0.49 to fix rounding (there are conversions from unsigned short to GLdouble and back)
+ (GLubyte)(((GLdouble)(bar + 2)
+ / (GLdouble)(m_data->d_ptr->row().size() + 2))
+ * 255.0 + 0.49), // +0.49 to fix rounding (there are conversions from unsigned short to GLdouble and back)
+ 0);
+ // TODO: For debugging
+ //if (selection != prevSel) {
+ // qDebug() << selection.x() << selection .y() << selection.z();
+ // prevSel = selection;
+ //}
+ if (current == selection)
+ isSelectedType = SelectionBar;
+ return isSelectedType;
+}
+
+bool Q3DMapsPrivate::isValid(const QDataItem &item)
+{
+ bool retval = true;
+ if (item.d_ptr->value() < 0) {
+ qCritical("Data item value out of range");
+ retval = false;
+ } else if (item.d_ptr->position().x() < 0 || item.d_ptr->position().x() > m_areaSize.width()) {
+ qCritical("Data item x position out of range");
+ retval = false;
+ } else if (item.d_ptr->position().y() < 0 || item.d_ptr->position().y() > m_areaSize.height()) {
+ qCritical("Data item y position out of range");
+ retval = false;
+ }
+ return retval;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/q3dmaps.h b/src/datavis3d/engine/q3dmaps.h
new file mode 100644
index 00000000..37bf08e7
--- /dev/null
+++ b/src/datavis3d/engine/q3dmaps.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DMAPS_H
+#define Q3DMAPS_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+#include "QtDataVis3D/qdatavis3namespace.h"
+#include "q3dwindow.h"
+
+class QOpenGLShaderProgram;
+class QImage;
+class QRect;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Q3DMapsPrivate;
+class QDataItem;
+class QDataRow;
+class QDataSet;
+class LabelItem;
+
+class QTCOMMERCIALDATAVIS3D_EXPORT Q3DMaps : public Q3DWindow
+{
+ Q_OBJECT
+public:
+ enum AdjustmentDirection {
+ AdjustHeight = 0, // map value to y
+ AdjustWidth, // map value to x
+ AdjustDepth, // map value to z
+ AdjustRadius, // map value to x and z
+ AdjustAll // map value to all (x, y, z)
+ };
+
+public:
+ explicit Q3DMaps();
+ ~Q3DMaps();
+
+ void initialize();
+ void render();
+ void render(QPainter *painter);
+
+ // Add data item. New data item is appended to old data.
+ // ownership of data is transferred
+ bool addDataItem(QDataItem *dataItem);
+
+ // Add data set. New data is appended to old data.
+ // ownership of data is transferred
+ bool addData(const QVector<QDataItem*> &data);
+ // ownership of data is transferred
+ bool addData(const QDataRow &data);
+
+ // Add data set. Old data is deleted.
+ // ownership of data is transferred
+ bool setData(const QVector<QDataItem*> &data);
+ // ownership of data is transferred
+ bool setData(QDataRow *data);
+
+ // bar specifications; base thickness in x, y and z, enum to indicate which direction is increased with value
+ // TODO: Start using thickness also in adjustment direction; use it as a relative value.
+ // For example, in AdjustAll mode setting thickness to (0.1f, 1.0f, 0.5f) would apply value to
+ // x at 10%, y at 100% and z at 50%. If a dimension is not included, given thickness states its absolute value.
+ void setBarSpecs(const QVector3D &thickness = QVector3D(1.0f, 1.0f, 1.0f),
+ AdjustmentDirection direction = AdjustHeight);
+
+ // bar type; bars (=cubes), pyramids, cones, cylinders, balls, etc.
+ void setBarType(BarStyle style, bool smooth = false);
+
+ // override bar type with own mesh
+ void setMeshFileName(const QString &objFileName);
+
+ // Select preset camera placement
+ void setCameraPreset(CameraPreset preset);
+
+ // Set camera rotation if you don't want to use the presets (in horizontal (-180...180) and
+ // vertical (0...90) angles and distance in percentage (10...500))
+ void setCameraPosition(GLfloat horizontal, GLfloat vertical, GLint distance = 100);
+
+ // Set theme (bar colors, shaders, window color, background colors, light intensity and text colors are affected)
+ void setTheme(ColorTheme theme);
+
+ // Set color if you don't want to use themes. Set uniform to false if you want the (height) color to change from bottom to top
+ void setBarColor(QColor baseColor, QColor heightColor, bool uniform = true);
+
+ // TODO: valon siirto / asetus
+ // Change selection mode; single bar, bar and row, bar and column, or all
+ void setSelectionMode(SelectionMode mode);
+
+ // Set window title
+ void setWindowTitle(const QString &title);
+
+ // Font size adjustment (should it be in enum (smallest, smaller, small, normal, large, larger, largest), or just GLfloat?
+ void setFontSize(GLfloat fontsize);
+
+ // Set font
+ void setFont(const QFont &font);
+
+ // Label transparency adjustment
+ void setLabelTransparency(LabelTransparency transparency);
+
+ // Enable or disable background grid
+ void setGridEnabled(bool enable);
+
+ // Set area specs
+ void setAreaSpecs(const QRect &areaRect, const QImage &image);
+
+ // Set area image
+ void setImage(const QImage &image);
+
+ // Adjust shadow quality
+ void setShadowQuality(ShadowQuality quality);
+
+protected:
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void wheelEvent(QWheelEvent *event);
+ void resizeEvent(QResizeEvent *event);
+
+private:
+ void drawScene();
+ QScopedPointer<Q3DMapsPrivate> d_ptr;
+ Q_DISABLE_COPY(Q3DMaps);
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/q3dmaps_p.h b/src/datavis3d/engine/q3dmaps_p.h
new file mode 100644
index 00000000..f02ebc36
--- /dev/null
+++ b/src/datavis3d/engine/q3dmaps_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef Q3DMAPS_P_H
+#define Q3DMAPS_P_H
+
+#include "qdatavis3dglobal.h"
+#include "qdatavis3namespace.h"
+#include <QOpenGLFunctions>
+#include <QFont>
+
+class QOpenGLPaintDevice;
+
+class QPoint;
+class QSizeF;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Q3DMaps;
+class QDataItem;
+class QDataRow;
+class QDataSet;
+class ShaderHelper;
+class ObjectHelper;
+class TextureHelper;
+class Theme;
+class Drawer;
+
+class Q3DMapsPrivate : public QObject
+{
+public:
+ enum SelectionType {
+ SelectionNone = 0,
+ SelectionBar,
+ SelectionRow,
+ SelectionColumn
+ };
+
+ enum MousePressType {
+ MouseNone = 0,
+ MouseOnScene,
+ MouseOnOverview,
+ MouseOnZoom,
+ MouseRotating
+ };
+
+public:
+ Q3DMapsPrivate(Q3DMaps *q);
+ ~Q3DMapsPrivate();
+
+ void loadBarMesh();
+ void loadBackgroundMesh();
+ void loadGridLineMesh();
+ void loadLabelMesh();
+ void initShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initSelectionShader();
+ void initBackgroundShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initLabelShaders(const QString &vertexShader, const QString &fragmentShader);
+ void initDepthShader();
+ void initSelectionBuffer();
+ void initDepthBuffer();
+ void updateTextures();
+ void calculateSceneScalingFactors(const QRect &areaRect);
+ void calculateHeightAdjustment(const QPair<GLfloat, GLfloat> &limits);
+ void calculateTranslation(QDataItem *item);
+ SelectionType isSelected(GLint bar, const QVector3D &selection);
+ bool isValid(const QDataItem &item);
+
+ Q3DMaps *q_ptr;
+
+ QOpenGLPaintDevice *m_paintDevice;
+ ShaderHelper *m_barShader;
+ ShaderHelper *m_depthShader;
+ ShaderHelper *m_selectionShader;
+ ShaderHelper *m_backgroundShader;
+ ShaderHelper *m_labelShader;
+ ObjectHelper *m_barObj;
+ ObjectHelper *m_backgroundObj;
+ ObjectHelper *m_gridLineObj;
+ ObjectHelper *m_labelObj;
+ QString m_objFile;
+ MousePressType m_mousePressed;
+ QPoint m_mousePos;
+ GLint m_zoomLevel;
+ GLfloat m_zoomAdjustment;
+ GLfloat m_horizontalRotation;
+ GLfloat m_verticalRotation;
+ QVector3D m_barThickness;
+ GLfloat m_heightNormalizer;
+ GLfloat m_yAdjustment;
+ GLfloat m_scaleFactor;
+ Theme *m_theme;
+ bool m_isInitialized;
+ SelectionMode m_selectionMode;
+ QDataItem *m_selectedBar;
+ QDataRow *m_data;
+ QString m_axisLabelX;
+ QString m_axisLabelZ;
+ QString m_axisLabelY;
+ QRect m_sceneViewPort;
+ QRect m_zoomViewPort;
+ bool m_zoomActivated;
+ TextureHelper *m_textureHelper;
+ LabelTransparency m_labelTransparency;
+ QFont m_font;
+ Drawer *m_drawer;
+ QSizeF m_areaSize;
+ GLuint m_bgrTexture;
+ GLuint m_depthTexture;
+ GLuint m_selectionTexture;
+ GLuint m_depthFrameBuffer;
+ GLuint m_selectionFrameBuffer;
+ GLuint m_selectionDepthBuffer;
+ bool m_updateLabels;
+ bool m_gridEnabled;
+ Q3DMaps::AdjustmentDirection m_adjustDirection;
+ ShadowQuality m_shadowQuality;
+ GLfloat m_shadowQualityToShader;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/q3dwindow.cpp b/src/datavis3d/engine/q3dwindow.cpp
new file mode 100644
index 00000000..a172e7b6
--- /dev/null
+++ b/src/datavis3d/engine/q3dwindow.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "q3dwindow.h"
+#include "q3dwindow_p.h"
+
+#include <QGuiApplication>
+
+#include <QOpenGLContext>
+#include <QOpenGLPaintDevice>
+#include <QPainter>
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+Q3DWindow::Q3DWindow(QWindow *parent)
+ : QWindow(parent),
+ d_ptr(new Q3DWindowPrivate(this))
+{
+ setSurfaceType(QWindow::OpenGLSurface);
+ QSurfaceFormat surfaceFormat;
+ surfaceFormat.setDepthBufferSize(16);
+ surfaceFormat.setSamples(4);
+ surfaceFormat.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ //surfaceFormat.setRenderableType(QSurfaceFormat::OpenGLES); // OpenGL crashes with ANGLE, comment out or define OpenGLES
+ setFormat(surfaceFormat);
+
+ create();
+
+ d_ptr->m_context->setFormat(requestedFormat());
+ d_ptr->m_context->create();
+#if !defined(Q_OS_MAC)
+ // These are required here for windows (and linux?), but cause errors on mac
+ d_ptr->m_context->makeCurrent(this);
+ initializeOpenGLFunctions();
+#endif
+ initialize();
+}
+
+Q3DWindow::~Q3DWindow()
+{
+}
+
+void Q3DWindow::initialize()
+{
+ qDebug() << "OpenGL version" << format().majorVersion() << format().minorVersion();
+ qDebug() << "OpenGL renderer" << format().renderableType();
+ //qDebug() << "OpenGL swapBehavior" << format().swapBehavior();
+ setAnimating(true);
+}
+
+void Q3DWindow::render()
+{
+}
+
+void Q3DWindow::renderLater()
+{
+ if (!d_ptr->m_updatePending) {
+ d_ptr->m_updatePending = true;
+ QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
+ }
+}
+
+bool Q3DWindow::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::UpdateRequest:
+ renderNow();
+ return true;
+ default:
+ return QWindow::event(event);
+ }
+}
+
+void Q3DWindow::exposeEvent(QExposeEvent *event)
+{
+ Q_UNUSED(event);
+
+ if (isExposed())
+ renderNow();
+}
+
+void Q3DWindow::renderNow()
+{
+ if (!isExposed())
+ return;
+
+ static bool needsInit = true;
+
+ d_ptr->m_updatePending = false;
+
+ d_ptr->m_context->makeCurrent(this);
+
+ if (needsInit) {
+#if defined(Q_OS_MAC)
+ initializeOpenGLFunctions();
+#endif
+ initialize();
+ needsInit = false;
+ }
+
+ render();
+
+ d_ptr->m_context->swapBuffers(this);
+
+ if (d_ptr->m_animating)
+ renderLater();
+}
+
+void Q3DWindow::setAnimating(bool animating)
+{
+ d_ptr->m_animating = animating;
+
+ if (animating)
+ renderLater();
+}
+
+Q3DWindowPrivate::Q3DWindowPrivate(Q3DWindow *q)
+ : q_ptr(q),
+ m_updatePending(false),
+ m_animating(false),
+ m_context(new QOpenGLContext(q))
+{
+}
+
+Q3DWindowPrivate::~Q3DWindowPrivate()
+{
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/q3dwindow.h b/src/datavis3d/engine/q3dwindow.h
new file mode 100644
index 00000000..9958f7d9
--- /dev/null
+++ b/src/datavis3d/engine/q3dwindow.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q3DWINDOW_H
+#define Q3DWINDOW_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+
+#include <QWindow>
+#include <QOpenGLFunctions>
+
+class QPainter;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Q3DWindowPrivate;
+
+class QTCOMMERCIALDATAVIS3D_EXPORT Q3DWindow : public QWindow, protected QOpenGLFunctions
+{
+ Q_OBJECT
+public:
+ explicit Q3DWindow(QWindow *parent = 0);
+ ~Q3DWindow();
+
+ virtual void render();
+
+ virtual void initialize();
+
+ void setAnimating(bool animating);
+
+public slots:
+ void renderLater();
+ void renderNow();
+
+protected:
+ bool event(QEvent *event);
+ void exposeEvent(QExposeEvent *event);
+
+private:
+ QScopedPointer<Q3DWindowPrivate> d_ptr;
+
+ friend class Q3DBarsPrivate;
+ friend class Q3DBars;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/q3dwindow_p.h b/src/datavis3d/engine/q3dwindow_p.h
new file mode 100644
index 00000000..ef786fb3
--- /dev/null
+++ b/src/datavis3d/engine/q3dwindow_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef Q3DWINDOW_p_H
+#define Q3DWINDOW_p_H
+
+#include "qdatavis3dglobal.h"
+
+class QOpenGLContext;
+class QOpenGLPaintDevice;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Q3DWindow;
+
+class Q3DWindowPrivate
+{
+public:
+ Q3DWindowPrivate(Q3DWindow *q);
+ ~Q3DWindowPrivate();
+
+public:
+ Q3DWindow *q_ptr;
+
+ bool m_updatePending;
+ bool m_animating;
+
+ QOpenGLContext *m_context;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/qdataitem.cpp b/src/datavis3d/engine/qdataitem.cpp
new file mode 100644
index 00000000..14d6c85f
--- /dev/null
+++ b/src/datavis3d/engine/qdataitem.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdataitem.h"
+#include "qdataitem_p.h"
+
+#include <QPoint>
+#include <QString>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+QDataItem::QDataItem(float value, const QString &label)
+ : d_ptr(new QDataItemPrivate(this, value, label))
+{
+ //qDebug("QDataItem");
+}
+
+QDataItem::~QDataItem()
+{
+ //qDebug("~QDataItem");
+}
+
+void QDataItem::setLabel(const QString &label, bool prepend)
+{
+ d_ptr->m_labelString = label;
+ d_ptr->m_prependLabel = prepend;
+}
+
+void QDataItem::setValue(float value)
+{
+ d_ptr->m_value = value;
+}
+
+void QDataItem::setValue(int value)
+{
+ d_ptr->m_value = (float)value;
+}
+
+void QDataItem::setPosition(const QPointF &position)
+{
+ d_ptr->m_position = position;
+}
+
+void QDataItem::setPosition(const QPoint &position)
+{
+ d_ptr->m_position = (QPointF)position;
+}
+
+QDataItemPrivate::QDataItemPrivate(QDataItem *q, float value, const QString &label)
+ : q_ptr(q),
+ m_value(value),
+ m_labelString(label),
+ m_prependLabel(false),
+ m_translation(QVector3D(0, 0, 0)),
+ m_label(LabelItem()),
+ m_selectionLabel(LabelItem())
+{
+}
+
+QDataItemPrivate::~QDataItemPrivate()
+{
+}
+
+void QDataItemPrivate::setTranslation(const QVector3D &translation)
+{
+ m_translation = translation;
+}
+
+QVector3D QDataItemPrivate::translation()
+{
+ return m_translation;
+}
+
+float QDataItemPrivate::value()
+{
+ return m_value;
+}
+
+QString QDataItemPrivate::valueStr()
+{
+ QString strVal;
+ QString numStr;
+ numStr.setNum(m_value);
+ if (m_prependLabel) {
+ strVal.append(m_labelString);
+ strVal.append(QStringLiteral(" "));
+ strVal.append(numStr);
+ } else {
+ strVal.append(numStr);
+ strVal.append(m_labelString);
+ }
+ return strVal;
+}
+
+void QDataItemPrivate::setLabel(const LabelItem &label)
+{
+ m_label = label;
+}
+
+LabelItem QDataItemPrivate::label()
+{
+ return m_label;
+}
+
+void QDataItemPrivate::setSelectionLabel(const LabelItem &label)
+{
+ m_selectionLabel = label;
+}
+
+LabelItem QDataItemPrivate::selectionLabel()
+{
+ return m_selectionLabel;
+}
+
+QPointF QDataItemPrivate::position()
+{
+ return m_position;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/qdataitem.h b/src/datavis3d/engine/qdataitem.h
new file mode 100644
index 00000000..88d54faf
--- /dev/null
+++ b/src/datavis3d/engine/qdataitem.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATAITEM_H
+#define QDATAITEM_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+#include <QScopedPointer>
+#include <QString>
+
+class QPointF;
+class QPoint;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class QDataItemPrivate;
+
+class QTCOMMERCIALDATAVIS3D_EXPORT QDataItem
+{
+public:
+ explicit QDataItem(float value = 0.0f, const QString &label = QString());
+ ~QDataItem();
+
+ void setLabel(const QString &label, bool prepend = false); // label for value, unit for example
+ void setValue(float value);
+ void setValue(int value);
+ // Has no effect in Q3DBars
+ void setPosition(const QPointF &position);
+ void setPosition(const QPoint &position);
+
+private:
+ QScopedPointer<QDataItemPrivate> d_ptr;
+ friend class Q3DBars;
+ friend class Q3DBarsPrivate;
+ friend class Q3DMaps;
+ friend class Q3DMapsPrivate;
+ friend class QDataRowPrivate;
+ friend class Drawer;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/qdataitem_p.h b/src/datavis3d/engine/qdataitem_p.h
new file mode 100644
index 00000000..f14fe175
--- /dev/null
+++ b/src/datavis3d/engine/qdataitem_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QDATAITEM_P_H
+#define QDATAITEM_P_H
+
+#include "qdatavis3dglobal.h"
+#include "qdataitem.h"
+#include "labelitem_p.h"
+#include <QOpenGLFunctions>
+#include <QSize>
+#include <QString>
+#include <QVector3D>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class QDataItemPrivate
+{
+ public:
+ explicit QDataItemPrivate(QDataItem *q, float value = 0.0f,
+ const QString &label = QString());
+ ~QDataItemPrivate();
+
+ // Position in 3D scene
+ void setTranslation(const QVector3D &translation);
+ QVector3D translation();
+ // Value of bar
+ float value();
+ // Value and label appended into a string. If label has prepend -flag set, append label and value
+ QString valueStr();
+ // Label item (containing valueStr as texture)
+ void setLabel(const LabelItem &label);
+ LabelItem label();
+ // Selection label item (containing specialar selection texture, if mode is activated)
+ void setSelectionLabel(const LabelItem &label);
+ LabelItem selectionLabel();
+ QPointF position();
+
+ private:
+ QDataItem *q_ptr;
+ float m_value;
+ QString m_labelString;
+ bool m_prependLabel;
+ QVector3D m_translation;
+ LabelItem m_label;
+ LabelItem m_selectionLabel;
+ QPointF m_position;
+ friend class QDataItem;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/qdatarow.cpp b/src/datavis3d/engine/qdatarow.cpp
new file mode 100644
index 00000000..f4a9e984
--- /dev/null
+++ b/src/datavis3d/engine/qdatarow.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdatarow.h"
+#include "qdatarow_p.h"
+#include "qdataitem.h"
+#include "qdataitem_p.h"
+
+#include <QString>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+QDataRow::QDataRow(const QString &label)
+ : d_ptr(new QDataRowPrivate(this, label))
+{
+ //qDebug("QDataRow");
+}
+
+QDataRow::~QDataRow()
+{
+ //qDebug("~QDataRow");
+}
+
+void QDataRow::setLabel(const QString &label)
+{
+ d_ptr->m_label = label;
+}
+
+void QDataRow::addItem(QDataItem *item)
+{
+ d_ptr->m_row.prepend(item);
+}
+
+QDataRowPrivate::QDataRowPrivate(QDataRow *q, const QString &label)
+ : q_ptr(q),
+ m_label(label),
+ m_labelItem(LabelItem())
+{
+}
+
+QDataRowPrivate::~QDataRowPrivate()
+{
+ for (int itemCount = 0; itemCount < m_row.size(); itemCount++)
+ delete m_row.at(itemCount);
+ m_row.clear();
+}
+
+QVector<QDataItem*> QDataRowPrivate::row()
+{
+ return m_row;
+}
+
+void QDataRowPrivate::clear()
+{
+ m_row.clear();
+}
+
+QDataItem *QDataRowPrivate::getItem(int itemIndex)
+{
+ QDataItem *item = NULL;
+ if (m_row.size() > itemIndex)
+ item = m_row.at(itemIndex);
+ return item;
+}
+
+void QDataRowPrivate::verifySize(int size)
+{
+ if (size > m_row.size()) {
+ // QVector's resize doesn't delete data contained in it
+ // Delete contents of items to be removed
+ int nbrToBeRemoved = m_row.size() - size;
+ for (int itemCount = 0; itemCount < nbrToBeRemoved; itemCount++) {
+ int itemToBeRemoved = m_row.size() - itemCount - 1; // -1 to compensate index 0
+ delete m_row.at(itemToBeRemoved);
+ }
+ // Resize vector
+ m_row.resize(size);
+ } else if (size < m_row.size()) {
+ qCritical("Check your sample space size! Your row is too short.");
+ }
+}
+
+QPair<GLfloat, GLfloat> QDataRowPrivate::limitValues()
+{
+ QPair<GLfloat, GLfloat> limits = qMakePair(100.0f, -100.0f);
+ for (int i = 0; i < m_row.size(); i++) {
+ QDataItem *item = m_row.at(i);
+ float itemValue = item->d_ptr->value();
+ if (limits.second < itemValue)
+ limits.second = itemValue;
+ if (limits.first > itemValue)
+ limits.first = itemValue;
+ }
+ return limits;
+}
+
+QString QDataRowPrivate::label()
+{
+ return m_label;
+}
+
+void QDataRowPrivate::setLabelItem(const LabelItem &item)
+{
+ m_labelItem = item;
+}
+
+LabelItem QDataRowPrivate::labelItem()
+{
+ return m_labelItem;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/qdatarow.h b/src/datavis3d/engine/qdatarow.h
new file mode 100644
index 00000000..766ae541
--- /dev/null
+++ b/src/datavis3d/engine/qdatarow.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATAROW_H
+#define QDATAROW_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+#include <QScopedPointer>
+#include <QString>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class QDataRowPrivate;
+class QDataItem;
+
+class QTCOMMERCIALDATAVIS3D_EXPORT QDataRow
+{
+public:
+ explicit QDataRow(const QString &label = QString());
+ ~QDataRow();
+
+ void setLabel(const QString &label); // label for value, unit for example
+ void addItem(QDataItem *item);
+
+private:
+ QScopedPointer<QDataRowPrivate> d_ptr;
+ friend class Q3DBars;
+ friend class Q3DBarsPrivate;
+ friend class Q3DMaps;
+ friend class Q3DMapsPrivate;
+ friend class QDataSetPrivate;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/qdatarow_p.h b/src/datavis3d/engine/qdatarow_p.h
new file mode 100644
index 00000000..3a1adeee
--- /dev/null
+++ b/src/datavis3d/engine/qdatarow_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QDATAROW_P_H
+#define QDATAROW_P_H
+
+#include "qdatavis3dglobal.h"
+#include "qdatarow.h"
+#include "labelitem_p.h"
+#include <QVector>
+#include <QString>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class QDataItem;
+
+class QDataRowPrivate
+{
+public:
+ explicit QDataRowPrivate(QDataRow *q, const QString &label = QString());
+ ~QDataRowPrivate();
+
+ QVector<QDataItem*> row();
+ // Clears vector, doesn't delete items
+ void clear();
+ QDataItem *getItem(int itemIndex);
+ void verifySize(int size);
+ QPair<GLfloat, GLfloat> limitValues();
+ QString label();
+ void setLabelItem(const LabelItem &item);
+ LabelItem labelItem();
+
+private:
+ QDataRow *q_ptr;
+ QVector<QDataItem*> m_row;
+ QString m_label;
+ LabelItem m_labelItem;
+ friend class QDataRow;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/qdataset.cpp b/src/datavis3d/engine/qdataset.cpp
new file mode 100644
index 00000000..5af920d2
--- /dev/null
+++ b/src/datavis3d/engine/qdataset.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdataset.h"
+#include "qdataset_p.h"
+#include "qdatarow.h"
+#include "qdatarow_p.h"
+
+#include <QPoint>
+#include <QString>
+
+//#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+const QString empty;
+
+QDataSet::QDataSet()
+ : d_ptr(new QDataSetPrivate(this))
+{
+ //qDebug("QDataSet");
+}
+
+QDataSet::~QDataSet()
+{
+ //qDebug("~QDataSet");
+}
+
+void QDataSet::setLabels(const QString &xAxis,
+ const QString &zAxis,
+ const QString &yAxis,
+ const QVector<QString> &labelsRow,
+ const QVector<QString> &labelsColumn)
+{
+ // skip empty labels, keep the previous ones
+ if (xAxis != empty && d_ptr->m_xAxis != xAxis) {
+ d_ptr->m_xAxis = xAxis;
+ // Generate axis label texture
+ if (d_ptr->m_drawer)
+ d_ptr->m_drawer->generateLabelItem(&d_ptr->m_xAxisItem, xAxis);
+ }
+ if (zAxis != empty && d_ptr->m_zAxis != zAxis) {
+ d_ptr->m_zAxis = zAxis;
+ // Generate axis label texture
+ if (d_ptr->m_drawer)
+ d_ptr->m_drawer->generateLabelItem(&d_ptr->m_zAxisItem, zAxis);
+ }
+ if (yAxis != empty && d_ptr->m_yAxis != yAxis) {
+ d_ptr->m_yAxis = yAxis;
+ // Generate axis label texture
+ if (d_ptr->m_drawer)
+ d_ptr->m_drawer->generateLabelItem(&d_ptr->m_yAxisItem, yAxis);
+ }
+ d_ptr->m_labelsRow = labelsRow;
+ d_ptr->m_labelsColumn = labelsColumn;
+ // Generate row and column label textures
+ if (d_ptr->m_drawer) {
+ for (int itemCount = 0; itemCount < labelsColumn.size(); itemCount++) {
+ d_ptr->m_labelItemsColumn.append(LabelItem());
+ d_ptr->m_drawer->generateLabelItem(&d_ptr->m_labelItemsColumn[itemCount],
+ labelsColumn.at(itemCount));
+ }
+ for (int itemCount = 0; itemCount < labelsRow.size(); itemCount++) {
+ d_ptr->m_labelItemsRow.append(LabelItem());
+ d_ptr->m_drawer->generateLabelItem(&d_ptr->m_labelItemsRow[itemCount],
+ labelsRow.at(itemCount));
+ }
+ }
+}
+
+void QDataSet::addRow(QDataRow *row)
+{
+ d_ptr->m_set.prepend(row);
+}
+
+QDataSetPrivate::QDataSetPrivate(QDataSet *q)
+ : q_ptr(q),
+ m_set(QVector<QDataRow*>()),
+ m_xAxis(QString()),
+ m_zAxis(QString()),
+ m_yAxis(QString()),
+ m_labelsRow(QVector<QString>()),
+ m_labelsColumn(QVector<QString>()),
+ m_xAxisItem(LabelItem()),
+ m_zAxisItem(LabelItem()),
+ m_yAxisItem(LabelItem()),
+ m_labelItemsRow(QVector<LabelItem>()),
+ m_labelItemsColumn(QVector<LabelItem>()),
+ m_drawer(0)
+{
+}
+
+QDataSetPrivate::~QDataSetPrivate()
+{
+ for (int itemCount = 0; itemCount < m_set.size(); itemCount++)
+ delete m_set.at(itemCount);
+ m_set.clear();
+ // Delete axis textures
+ GLuint textureid = m_xAxisItem.textureId();
+ if (textureid)
+ glDeleteTextures(1, &textureid);
+ textureid = m_zAxisItem.textureId();
+ if (textureid)
+ glDeleteTextures(1, &textureid);
+ textureid = m_yAxisItem.textureId();
+ if (textureid)
+ glDeleteTextures(1, &textureid);
+ // Delete row and column textures
+ for (int itemCount = 0; itemCount < m_labelItemsColumn.size(); itemCount++) {
+ LabelItem item = m_labelItemsColumn.at(itemCount);
+ textureid = item.textureId();
+ if (textureid)
+ glDeleteTextures(1, &textureid);
+ }
+ for (int itemCount = 0; itemCount < m_labelItemsRow.size(); itemCount++) {
+ LabelItem item = m_labelItemsRow.at(itemCount);
+ textureid = item.textureId();
+ if (textureid)
+ glDeleteTextures(1, &textureid);
+ }
+}
+
+void QDataSetPrivate::setDrawer(Drawer *drawer)
+{
+ m_drawer = drawer;
+ connect(m_drawer, SIGNAL(drawerChanged()), this, SLOT(updateTextures()));
+ updateTextures();
+}
+
+QVector<QDataRow*> QDataSetPrivate::set()
+{
+ return m_set;
+}
+
+QDataRow *QDataSetPrivate::getRow(int rowIndex)
+{
+ QDataRow *row = NULL;
+ if (m_set.size() > rowIndex)
+ row = m_set.at(rowIndex);
+ return row;
+}
+
+QVector<QString> QDataSetPrivate::rowLabels()
+{
+ return m_labelsRow;
+}
+
+QVector<QString> QDataSetPrivate::columnLabels()
+{
+ return m_labelsColumn;
+}
+
+QVector<LabelItem> QDataSetPrivate::rowLabelItems()
+{
+ return m_labelItemsRow;
+}
+
+QVector<LabelItem> QDataSetPrivate::columnLabelItems()
+{
+ return m_labelItemsColumn;
+}
+
+void QDataSetPrivate::axisLabels(QString *xAxis, QString *zAxis, QString *yAxis)
+{
+ *xAxis = m_xAxis;
+ *zAxis = m_zAxis;
+ *yAxis = m_yAxis;
+}
+
+void QDataSetPrivate::axisLabelItems(LabelItem *xAxisItem, LabelItem *zAxisItem,
+ LabelItem *yAxisItem)
+{
+ *xAxisItem = m_xAxisItem;
+ *zAxisItem = m_zAxisItem;
+ *yAxisItem = m_yAxisItem;
+}
+
+void QDataSetPrivate::verifySize(int colSize, int rowSize)
+{
+ // First verify columns
+ // QVector's resize doesn't delete data contained in it
+ // Delete contents of rows to be removed
+ if (colSize < m_set.size()) {
+ int nbrToBeRemoved = m_set.size() - colSize;
+ for (int rowCount = 0; rowCount < nbrToBeRemoved; rowCount++) {
+ int rowToBeRemoved = m_set.size() - rowCount - 1; // -1 to compensate index 0
+ delete m_set.at(rowToBeRemoved);
+ }
+ // Resize vector
+ m_set.resize(colSize);
+ }
+ // Then verify each row left
+ if (rowSize) {
+ for (int i = 0; i < m_set.size(); i++)
+ m_set.at(i)->d_ptr->verifySize(rowSize);
+ }
+}
+
+QPair<GLfloat, GLfloat> QDataSetPrivate::limitValues()
+{
+ QPair<GLfloat, GLfloat> limits = qMakePair(100.0f, -100.0f);
+ QPair<GLfloat, GLfloat> rowLimits;
+ for (int i = 0; i < m_set.size(); i++) {
+ rowLimits = m_set.at(i)->d_ptr->limitValues();
+ if (limits.second < rowLimits.second)
+ limits.second = rowLimits.second;
+ if (limits.first > rowLimits.first)
+ limits.first = rowLimits.first;
+ }
+ return limits;
+}
+
+void QDataSetPrivate::updateTextures()
+{
+ if (m_xAxis != empty)
+ m_drawer->generateLabelItem(&m_xAxisItem, m_xAxis);
+ if (m_zAxis != empty)
+ m_drawer->generateLabelItem(&m_zAxisItem, m_zAxis);
+ if (m_yAxis != empty)
+ m_drawer->generateLabelItem(&m_yAxisItem, m_yAxis);
+ for (int itemCount = 0; itemCount < m_labelsColumn.size(); itemCount++) {
+ if (m_labelItemsColumn.size() < itemCount + 1)
+ m_labelItemsColumn.append(LabelItem());
+ m_drawer->generateLabelItem(&m_labelItemsColumn[itemCount], m_labelsColumn.at(itemCount));
+ }
+ for (int itemCount = 0; itemCount < m_labelsRow.size(); itemCount++) {
+ if (m_labelItemsRow.size() < itemCount + 1)
+ m_labelItemsRow.append(LabelItem());
+ m_drawer->generateLabelItem(&m_labelItemsRow[itemCount], m_labelsRow.at(itemCount));
+ }
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/qdataset.h b/src/datavis3d/engine/qdataset.h
new file mode 100644
index 00000000..118d3df9
--- /dev/null
+++ b/src/datavis3d/engine/qdataset.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDATASET_H
+#define QDATASET_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+#include "qdataitem.h"
+#include "qdatarow.h"
+
+#include <QScopedPointer>
+#include <QVector>
+#include <QString>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class QDataSetPrivate;
+
+class QTCOMMERCIALDATAVIS3D_EXPORT QDataSet
+{
+public:
+ explicit QDataSet();
+ ~QDataSet();
+
+ void setLabels(const QString &xAxis = QString(),
+ const QString &zAxis = QString(),
+ const QString &yAxis = QString(),
+ const QVector<QString> &labelsRow = QVector<QString>(),
+ const QVector<QString> &labelsColumn = QVector<QString>());
+ void addRow(QDataRow *row);
+
+private:
+ QScopedPointer<QDataSetPrivate> d_ptr;
+ friend class Q3DBars;
+ friend class Q3DBarsPrivate;
+ friend class Q3DMaps;
+ friend class Q3DMapsPrivate;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/qdataset_p.h b/src/datavis3d/engine/qdataset_p.h
new file mode 100644
index 00000000..90dc5329
--- /dev/null
+++ b/src/datavis3d/engine/qdataset_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QDATASET_P_H
+#define QDATASET_P_H
+
+#include "qdatavis3dglobal.h"
+#include "qdataset.h"
+#include "drawer_p.h"
+#include "labelitem_p.h"
+#include <QVector>
+#include <QString>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class QDataSetPrivate : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QDataSetPrivate(QDataSet *q);
+ ~QDataSetPrivate();
+
+ void setDrawer(Drawer *drawer);
+ QVector<QDataRow*> set();
+ QDataRow *getRow(int rowIndex);
+ QVector<QString> rowLabels();
+ QVector<QString> columnLabels();
+ QVector<LabelItem> rowLabelItems();
+ QVector<LabelItem> columnLabelItems();
+ void axisLabels(QString *xAxis, QString *zAxis, QString *yAxis);
+ void axisLabelItems(LabelItem *xAxisItem, LabelItem *zAxisItem, LabelItem *yAxisItem);
+ void verifySize(int colSize, int rowSize = 0); // If rowSize is 0, don't verify rows
+ // first = min, second = max
+ QPair<GLfloat, GLfloat> limitValues();
+
+public Q_SLOTS:
+ void updateTextures();
+
+private:
+ QDataSet *q_ptr;
+ QVector<QDataRow*> m_set;
+ QString m_xAxis;
+ QString m_zAxis;
+ QString m_yAxis;
+ QVector<QString> m_labelsRow;
+ QVector<QString> m_labelsColumn;
+ LabelItem m_xAxisItem;
+ LabelItem m_zAxisItem;
+ LabelItem m_yAxisItem;
+ QVector<LabelItem> m_labelItemsRow;
+ QVector<LabelItem> m_labelItemsColumn;
+ Drawer *m_drawer;
+ friend class QDataSet;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/engine/shaders/fragmentDepthTest b/src/datavis3d/engine/shaders/fragmentDepthTest
new file mode 100644
index 00000000..d6c502e1
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentDepthTest
@@ -0,0 +1,7 @@
+uniform sampler2D textureSampler;
+
+varying highp vec2 UV;
+
+void main() {
+ gl_FragColor = texture2D(textureSampler, UV);
+}
diff --git a/src/datavis3d/engine/shaders/fragmentShader b/src/datavis3d/engine/shaders/fragmentShader
new file mode 100644
index 00000000..5bf9c654
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShader
@@ -0,0 +1,36 @@
+#version 120
+
+varying highp vec2 UV;
+varying highp vec2 coords_mdl;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+void main() {
+ highp vec3 materialDiffuseColor = color_mdl.rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * pow(cosTheta, 2) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavis3d/engine/shaders/fragmentShaderAmbient b/src/datavis3d/engine/shaders/fragmentShaderAmbient
new file mode 100644
index 00000000..88f850f3
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShaderAmbient
@@ -0,0 +1,32 @@
+#version 120
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ highp vec3 lightColor = vec3(1.0, 1.0, 1.0);
+ highp float lightPower = 10.0;
+ highp vec3 materialAmbientColor = vec3(0.5, 0.5, 0.5) * color_mdl;
+ highp vec3 materialSpecularColor = vec3(0.3, 0.3, 0.3) * color_mdl;
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialSpecularColor * lightColor * lightPower * pow(cosAlpha, 5) / (distance * distance);
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavis3d/engine/shaders/fragmentShaderColorOnY b/src/datavis3d/engine/shaders/fragmentShaderColorOnY
new file mode 100644
index 00000000..ee57e8e5
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShaderColorOnY
@@ -0,0 +1,33 @@
+#version 120
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+void main() {
+ highp vec3 materialDiffuseColor = vec3(coords_mdl.y * color_mdl.x, coords_mdl.y * color_mdl.y, coords_mdl.y * color_mdl.z);
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / (distance * distance) +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 5) / (distance * distance);
+}
+
diff --git a/src/datavis3d/engine/shaders/fragmentShaderDepth b/src/datavis3d/engine/shaders/fragmentShaderDepth
new file mode 100644
index 00000000..5cfd4b10
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShaderDepth
@@ -0,0 +1,3 @@
+void main() {
+ gl_FragDepth = gl_FragCoord.z;
+}
diff --git a/src/datavis3d/engine/shaders/fragmentShaderLabel b/src/datavis3d/engine/shaders/fragmentShaderLabel
new file mode 100644
index 00000000..86021410
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShaderLabel
@@ -0,0 +1,8 @@
+uniform sampler2D textureSampler;
+
+varying highp vec2 UV;
+
+void main() {
+ gl_FragColor = texture2D(textureSampler, UV);
+}
+
diff --git a/src/datavis3d/engine/shaders/fragmentShaderSelection b/src/datavis3d/engine/shaders/fragmentShaderSelection
new file mode 100644
index 00000000..66370224
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShaderSelection
@@ -0,0 +1,7 @@
+uniform highp vec3 color_mdl;
+//uniform highp vec4 color_mdl;
+void main() {
+ gl_FragColor.rgb = color_mdl;
+ //gl_FragColor = color_mdl;
+}
+
diff --git a/src/datavis3d/engine/shaders/fragmentShaderTexture b/src/datavis3d/engine/shaders/fragmentShaderTexture
new file mode 100644
index 00000000..d271f985
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShaderTexture
@@ -0,0 +1,35 @@
+#version 120
+
+uniform highp vec3 lightPosition_wrld;
+uniform highp vec3 color_mdl;
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform sampler2D textureSampler;
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp float distance = length(lightPosition_wrld - position_wrld);
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ gl_FragColor.rgb =
+ materialAmbientColor +
+ materialDiffuseColor * lightStrength * (cosTheta * cosTheta) / distance +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10) / distance;
+ gl_FragColor.a = 1.0;
+}
+
diff --git a/src/datavis3d/engine/shaders/fragmentShadow b/src/datavis3d/engine/shaders/fragmentShadow
new file mode 100644
index 00000000..3a6ffc5a
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShadow
@@ -0,0 +1,140 @@
+#version 120
+//#version 130 // use with version 1
+
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp float shadowQuality;
+uniform highp sampler2D textureSampler;
+uniform highp sampler2DShadow shadowMap; // use with version 2
+//uniform highp sampler2D shadowMap; // use with version 1
+
+varying highp vec4 shadowCoord;
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+const highp vec2 poissonDisk[16] = vec2[](vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790));
+
+/*float random(vec3 seed, int i) {
+ vec4 seed4 = vec4(seed, i);
+ float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673));
+ return fract(sin(dot_product) * 43758.5453);
+}*/
+
+// Version 1: Causes self-shadowing, but shadows are smooth
+/*void main() {
+ float shadowFactor = 1.0; // default to '1' meaning "no shadow"
+ //float epsilon = 0.01; // increase value to remove little artifacts
+ vec4 shadCoordsPD = shadowCoord;
+ shadCoordsPD.z += 0.005;
+ shadCoordsPD /= shadowCoord.w;
+ if (shadowCoord.w <= 0.0) { // ignore negative projection
+ shadowFactor = 1.0;
+ } else if (shadCoordsPD.x < 0.0 || shadCoordsPD.y < 0.0) { // outside light frustum, ignore
+ shadowFactor = 1.0;
+ } else if (shadCoordsPD.x >= 1.0 || shadCoordsPD.y >= 1.0) { // outside light frustum, ignore
+ shadowFactor = 1.0;
+ } else {
+ // This does not work perfectly. It causes self-shadowing, which we should get rid of.
+ // Requires at least #version 130
+ float shadow = 0.0;
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(0, 0));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(-1, 1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(1, 1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(-1, -1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(1, -1));
+ shadow *= 0.2;
+ shadowFactor = shadow;
+ //float shadow = texture2D(shadowMap, shadCoordsPD.xy).x;
+ //if (shadow + epsilon < shadCoordsPD.z) {
+ // shadowFactor = 0.0;
+ //}
+ }
+ // shadow is dark gray, other parts light gray
+ //gl_FragColor = vec4(0.8, 0.8, 0.8, 1.0) * shadowFactor;// + vec4(0.2, 0.2, 0.2, 1.0);
+ // simple shadows with no effect from light
+ //gl_FragColor = texture2D(textureSampler, UV) * shadowFactor;
+
+ // shadows including effects from light
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(0.2, 0.2, 0.2);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ // Shadow strength can be adjusted by using pow(shadowFactor, strength), but it causes self-shadowing issues that need to be solved
+ gl_FragColor.rgb =
+ shadowFactor * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10));
+ gl_FragColor.a = 1.0;
+}*/
+
+// Version 2: Shadows are a bit rugged (may be fixed with poisson disk?)
+void main() {
+ highp vec3 materialDiffuseColor = texture2D(textureSampler, UV).rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(0.2, 0.2, 0.2);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ highp float bias = 0.005 * tan(acos(cosTheta));
+ bias = clamp(bias, 0.0, 0.01);
+
+ vec4 shadCoords = shadowCoord;
+ shadCoords.z -= bias;
+ // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1)
+ // direct method; needs large shadow texture to look good
+ //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25;
+ // poisson disk sampling; smoothes edges
+ highp float visibility = 0.2;
+ for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality;
+ shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ // stratified poisson; produces noise but hides pixel edges well
+ /*for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ int index = int(16.0 * random(gl_FragCoord.xyy, i));
+ shadCoordsPD.xy += poissonDisk[index] / 150.0;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ */
+
+ gl_FragColor.rgb =
+ visibility * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10));
+ gl_FragColor.a = 1.0;
+}
diff --git a/src/datavis3d/engine/shaders/fragmentShadowNoTex b/src/datavis3d/engine/shaders/fragmentShadowNoTex
new file mode 100644
index 00000000..a08b6b40
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShadowNoTex
@@ -0,0 +1,147 @@
+#version 120
+//#version 130 // use with version 1
+
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp float shadowQuality;
+uniform highp vec3 color_mdl;
+uniform highp sampler2DShadow shadowMap; // use with version 2
+//uniform highp sampler2D shadowMap; // use with version 1
+
+varying highp vec4 shadowCoord;
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+const highp vec2 poissonDisk[16] = vec2[](vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790));
+
+/*const highp vec2 poissonDisk[16] = vec2[](vec2(-0.25, -0.25),
+ vec2(0.25, -0.25),
+ vec2(-0.25, 0.25),
+ vec2(0.25, 0.25),
+ vec2(-0.5, -0.5),
+ vec2(0.5, -0.5),
+ vec2(-0.5, 0.5),
+ vec2(0.5, 0.5),
+ vec2(-0.75, -0.75),
+ vec2(0.75, -0.75),
+ vec2(-0.75, 0.75),
+ vec2(0.75, 0.75),
+ vec2(-1.0, -1.0),
+ vec2(1.0, -1.0),
+ vec2(-1.0, 1.0),
+ vec2(1.0, 1.0));*/
+
+/*float random(vec3 seed, int i) {
+ vec4 seed4 = vec4(seed, i);
+ float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673));
+ return fract(sin(dot_product) * 43758.5453);
+}*/
+
+// Version 1: Causes self-shadowing, but shadows are smooth
+/*void main() {
+ float shadowFactor = 1.0; // default to '1' meaning "no shadow"
+ vec4 shadCoordsPD = shadowCoord;
+ shadCoordsPD.z += 0.005;
+ shadCoordsPD /= shadowCoord.w;
+ if (shadowCoord.w <= 0.0) { // ignore negative projection
+ shadowFactor = 1.0;
+ } else if (shadCoordsPD.x < 0.0 || shadCoordsPD.y < 0.0) { // outside light frustum, ignore
+ shadowFactor = 1.0;
+ } else if (shadCoordsPD.x >= 1.0 || shadCoordsPD.y >= 1.0) { // outside light frustum, ignore
+ shadowFactor = 1.0;
+ } else {
+ // This does not work perfectly. It causes self-shadowing, which we should get rid of.
+ // Requires at least #version 130
+ float shadow = 0.0;
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(0, 0));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(-1, 1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(1, 1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(-1, -1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(1, -1));
+ shadow *= 0.2;
+ shadowFactor = shadow;
+ }
+
+ highp vec3 materialDiffuseColor = color_mdl.rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ // Shadow strength can be adjusted by using pow(shadowFactor, strength), but it causes self-shadowing issues that need to be solved
+ gl_FragColor.rgb =
+ shadowFactor * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 20));
+ gl_FragColor.a = 1.0;
+}*/
+
+// Version 2: Shadows are a bit rugged (may be fixed with poisson disk?)
+void main() {
+ highp vec3 materialDiffuseColor = color_mdl.rgb;
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ highp float bias = 0.005 * tan(acos(cosTheta));
+ bias = clamp(bias, 0.0, 0.01);
+
+ vec4 shadCoords = shadowCoord;
+ shadCoords.z -= bias;
+ // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1)
+ // direct method; needs large shadow texture to look good
+ //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25;
+ // poisson disk sampling; smoothes edges
+ highp float visibility = 0.2;
+ for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality;
+ shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ // stratified poisson; produces noise but hides pixel edges well
+ /*for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ int index = int(16.0 * random(gl_FragCoord.xyy, i));
+ shadCoordsPD.xy += poissonDisk[index] / 150.0;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ */
+
+ gl_FragColor.rgb =
+ visibility * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10));
+ gl_FragColor.a = 1.0;
+}
diff --git a/src/datavis3d/engine/shaders/fragmentShadowNoTexColorOnY b/src/datavis3d/engine/shaders/fragmentShadowNoTexColorOnY
new file mode 100644
index 00000000..d208c5fd
--- /dev/null
+++ b/src/datavis3d/engine/shaders/fragmentShadowNoTexColorOnY
@@ -0,0 +1,128 @@
+#version 120
+//#version 130 // use with version 1
+
+uniform highp float lightStrength;
+uniform highp float ambientStrength;
+uniform highp float shadowQuality;
+uniform highp vec3 color_mdl;
+uniform highp sampler2DShadow shadowMap; // use with version 2
+//uniform highp sampler2D shadowMap; // use with version 1
+
+varying highp vec4 shadowCoord;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+const highp vec2 poissonDisk[16] = vec2[](vec2(-0.94201624, -0.39906216),
+ vec2(0.94558609, -0.76890725),
+ vec2(-0.094184101, -0.92938870),
+ vec2(0.34495938, 0.29387760),
+ vec2(-0.91588581, 0.45771432),
+ vec2(-0.81544232, -0.87912464),
+ vec2(-0.38277543, 0.27676845),
+ vec2(0.97484398, 0.75648379),
+ vec2(0.44323325, -0.97511554),
+ vec2(0.53742981, -0.47373420),
+ vec2(-0.26496911, -0.41893023),
+ vec2(0.79197514, 0.19090188),
+ vec2(-0.24188840, 0.99706507),
+ vec2(-0.81409955, 0.91437590),
+ vec2(0.19984126, 0.78641367),
+ vec2(0.14383161, -0.14100790));
+
+/*float random(vec3 seed, int i) {
+ vec4 seed4 = vec4(seed, i);
+ float dot_product = dot(seed4, vec4(12.9898, 78.233, 45.164, 94.673));
+ return fract(sin(dot_product) * 43758.5453);
+}*/
+
+// Version 1: Causes self-shadowing, but shadows are smooth
+/*void main() {
+ float shadowFactor = 1.0; // default to '1' meaning "no shadow"
+ vec4 shadCoordsPD = shadowCoord;
+ shadCoordsPD.z += 0.005;
+ shadCoordsPD /= shadowCoord.w;
+ if (shadowCoord.w <= 0.0) { // ignore negative projection
+ shadowFactor = 1.0;
+ } else if (shadCoordsPD.x < 0.0 || shadCoordsPD.y < 0.0) { // outside light frustum, ignore
+ shadowFactor = 1.0;
+ } else if (shadCoordsPD.x >= 1.0 || shadCoordsPD.y >= 1.0) { // outside light frustum, ignore
+ shadowFactor = 1.0;
+ } else {
+ // This does not work perfectly. It causes self-shadowing, which we should get rid of.
+ // Requires at least #version 130
+ float shadow = 0.0;
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(0, 0));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(-1, 1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(1, 1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(-1, -1));
+ shadow += textureProjOffset(shadowMap, shadCoordsPD, ivec2(1, -1));
+ shadow *= 0.2;
+ shadowFactor = shadow;
+ }
+
+ highp vec3 materialDiffuseColor = vec3(coords_mdl.y * color_mdl.x, coords_mdl.y * color_mdl.y, coords_mdl.y * color_mdl.z);
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ // Shadow strength can be adjusted by using pow(shadowFactor, strength), but it causes self-shadowing issues that need to be solved
+ gl_FragColor.rgb =
+ shadowFactor * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 20));
+ gl_FragColor.a = 1.0;
+}*/
+
+// Version 2: Shadows are a bit rugged (may be fixed with poisson disk?)
+void main() {
+ highp vec3 materialDiffuseColor = vec3(coords_mdl.y * color_mdl.x, coords_mdl.y * color_mdl.y, coords_mdl.y * color_mdl.z);
+ highp vec3 materialAmbientColor = vec3(ambientStrength, ambientStrength, ambientStrength) * materialDiffuseColor;
+ highp vec3 materialSpecularColor = vec3(1.0, 1.0, 1.0);
+
+ highp vec3 n = normalize(normal_cmr);
+ highp vec3 l = normalize(lightDirection_cmr);
+ highp float cosTheta = clamp(dot(n, l), 0.0, 1.0);
+
+ highp vec3 E = normalize(eyeDirection_cmr);
+ highp vec3 R = reflect(-l, n);
+ highp float cosAlpha = clamp(dot(E, R), 0.0, 1.0);
+
+ highp float bias = 0.005 * tan(acos(cosTheta));
+ bias = clamp(bias, 0.0, 0.01);
+
+ vec4 shadCoords = shadowCoord;
+ shadCoords.z -= bias;
+ // adjust shadow strength by increasing the multiplier and lowering the addition (their sum must be 1)
+ // direct method; needs large shadow texture to look good
+ //highp float visibility = 0.75 * shadow2DProj(shadowMap, shadCoords).r + 0.25;
+ // poisson disk sampling; smoothes edges
+ highp float visibility = 0.2;
+ for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ shadCoordsPD.x += cos(poissonDisk[i].x) / shadowQuality;
+ shadCoordsPD.y += sin(poissonDisk[i].y) / shadowQuality;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }
+ /*for (int i = 0; i < 15; i++) {
+ vec4 shadCoordsPD = shadCoords;
+ int index = int(16.0 * random(gl_FragCoord.xyy, i));
+ shadCoordsPD.xy += poissonDisk[index] / 150.0;
+ visibility += 0.05 * shadow2DProj(shadowMap, shadCoordsPD).r;
+ }*/
+
+ gl_FragColor.rgb =
+ visibility * (materialAmbientColor +
+ materialDiffuseColor * lightStrength * cosTheta +
+ materialSpecularColor * lightStrength * pow(cosAlpha, 10));
+ gl_FragColor.a = 1.0;
+}
diff --git a/src/datavis3d/engine/shaders/vertexDepthTest b/src/datavis3d/engine/shaders/vertexDepthTest
new file mode 100644
index 00000000..d62f1aa7
--- /dev/null
+++ b/src/datavis3d/engine/shaders/vertexDepthTest
@@ -0,0 +1,9 @@
+attribute highp vec3 vertexPosition_mdl;
+
+varying highp vec2 UV;
+
+void main() {
+ gl_Position = vec4(vertexPosition_mdl, 1.0);
+ UV = (vertexPosition_mdl.xy + vec2(1.0, 1.0)) / 2.0;
+}
+
diff --git a/src/datavis3d/engine/shaders/vertexShader b/src/datavis3d/engine/shaders/vertexShader
new file mode 100644
index 00000000..14f77773
--- /dev/null
+++ b/src/datavis3d/engine/shaders/vertexShader
@@ -0,0 +1,28 @@
+#version 120
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+attribute highp vec3 vertexNormal_mdl;
+
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec2 coords_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ coords_mdl = vertexPosition_mdl.xy;
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+}
diff --git a/src/datavis3d/engine/shaders/vertexShaderDepth b/src/datavis3d/engine/shaders/vertexShaderDepth
new file mode 100644
index 00000000..9fe5a193
--- /dev/null
+++ b/src/datavis3d/engine/shaders/vertexShaderDepth
@@ -0,0 +1,8 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+}
+
diff --git a/src/datavis3d/engine/shaders/vertexShaderLabel b/src/datavis3d/engine/shaders/vertexShaderLabel
new file mode 100644
index 00000000..b4debe53
--- /dev/null
+++ b/src/datavis3d/engine/shaders/vertexShaderLabel
@@ -0,0 +1,11 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+
+varying highp vec2 UV;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ UV = vertexUV;
+}
diff --git a/src/datavis3d/engine/shaders/vertexShaderSelection b/src/datavis3d/engine/shaders/vertexShaderSelection
new file mode 100644
index 00000000..64d17e15
--- /dev/null
+++ b/src/datavis3d/engine/shaders/vertexShaderSelection
@@ -0,0 +1,7 @@
+uniform highp mat4 MVP;
+
+attribute highp vec3 vertexPosition_mdl;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+}
diff --git a/src/datavis3d/engine/shaders/vertexShaderTexture b/src/datavis3d/engine/shaders/vertexShaderTexture
new file mode 100644
index 00000000..01f922e0
--- /dev/null
+++ b/src/datavis3d/engine/shaders/vertexShaderTexture
@@ -0,0 +1,26 @@
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp vec3 lightPosition_wrld;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec2 vertexUV;
+attribute highp vec3 vertexNormal_mdl;
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ vec3 lightPosition_cmr = (V * vec4(lightPosition_wrld, 1.0)).xyz;
+ lightDirection_cmr = lightPosition_cmr + eyeDirection_cmr;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ UV = vertexUV;
+}
diff --git a/src/datavis3d/engine/shaders/vertexShadow b/src/datavis3d/engine/shaders/vertexShadow
new file mode 100644
index 00000000..e29a8a30
--- /dev/null
+++ b/src/datavis3d/engine/shaders/vertexShadow
@@ -0,0 +1,37 @@
+#version 120
+
+uniform highp mat4 MVP;
+uniform highp mat4 V;
+uniform highp mat4 M;
+uniform highp mat4 itM;
+uniform highp mat4 depthMVP;
+uniform highp vec3 lightPosition_wrld;
+
+attribute highp vec3 vertexPosition_mdl;
+attribute highp vec3 vertexNormal_mdl;
+attribute highp vec2 vertexUV;
+
+varying highp vec2 UV;
+varying highp vec3 position_wrld;
+varying highp vec3 normal_cmr;
+varying highp vec3 eyeDirection_cmr;
+varying highp vec3 lightDirection_cmr;
+varying highp vec4 shadowCoord;
+varying highp vec2 coords_mdl;
+
+const highp mat4 bias = mat4(0.5, 0.0, 0.0, 0.0,
+ 0.0, 0.5, 0.0, 0.0,
+ 0.0, 0.0, 0.5, 0.0,
+ 0.5, 0.5, 0.5, 1.0);
+
+void main() {
+ gl_Position = MVP * vec4(vertexPosition_mdl, 1.0);
+ coords_mdl = vertexPosition_mdl.xy;
+ shadowCoord = bias * depthMVP * vec4(vertexPosition_mdl, 1.0);
+ position_wrld = (M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ vec3 vertexPosition_cmr = (V * M * vec4(vertexPosition_mdl, 1.0)).xyz;
+ eyeDirection_cmr = vec3(0.0, 0.0, 0.0) - vertexPosition_cmr;
+ lightDirection_cmr = (V * vec4(lightPosition_wrld, 0.0)).xyz;
+ normal_cmr = (V * itM * vec4(vertexNormal_mdl, 0.0)).xyz;
+ UV = vertexUV;
+}
diff --git a/src/datavis3d/engine/theme.cpp b/src/datavis3d/engine/theme.cpp
new file mode 100644
index 00000000..a9032e25
--- /dev/null
+++ b/src/datavis3d/engine/theme.cpp
@@ -0,0 +1,298 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "theme_p.h"
+
+#ifdef Q_OS_WIN
+#include <windows.h>
+#include <stdio.h>
+#endif
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+Theme::Theme()
+ : m_baseColor(QColor(Qt::gray)),
+ m_heightColor(QColor(Qt::black)),
+ m_depthColor(QColor(Qt::black)),
+ m_backgroundColor(QColor(Qt::gray)),
+ m_windowColor(QColor(Qt::gray)),
+ m_textColor(QColor(Qt::white)),
+ m_textBackgroundColor(QColor(0x00, 0x00, 0x00, 0x80)),
+ m_gridLine(QColor(Qt::black)),
+ m_highlightBarColor(QColor(Qt::red)),
+ m_highlightRowColor(QColor(Qt::darkRed)),
+ m_highlightColumnColor(QColor(Qt::darkMagenta)),
+ m_lightStrength(4.0f),
+ m_ambientStrength(0.3f),
+ m_highlightLightStrength(8.0f),
+ m_uniformColor(true)
+{
+}
+
+Theme::~Theme()
+{
+}
+
+void Theme::useTheme(ColorTheme theme)
+{
+ switch (theme) {
+ case ThemeSystem: {
+#ifdef Q_OS_WIN
+ DWORD colorHighlight;
+ colorHighlight = GetSysColor(COLOR_HIGHLIGHT);
+ m_baseColor = QColor(GetRValue(colorHighlight),
+ GetGValue(colorHighlight),
+ GetBValue(colorHighlight));
+ DWORD colorWindowFrame;
+ colorWindowFrame = GetSysColor(COLOR_WINDOWFRAME);
+ m_heightColor = QColor(GetRValue(colorWindowFrame),
+ GetGValue(colorWindowFrame),
+ GetBValue(colorWindowFrame));
+ m_depthColor = QColor(Qt::black);
+ DWORD colorWindow;
+ colorWindow = GetSysColor(COLOR_WINDOW);
+ m_backgroundColor = QColor(GetRValue(colorWindow),
+ GetGValue(colorWindow),
+ GetBValue(colorWindow));
+ m_windowColor = QColor(GetRValue(colorWindow),
+ GetGValue(colorWindow),
+ GetBValue(colorWindow));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xd6, 0xd6, 0xd6, 0x80);
+ m_gridLine = QColor(QRgb(0xe2e2e2));
+ m_highlightBarColor = QColor(QRgb(0xe2e2e2));
+ m_highlightRowColor = QColor(QRgb(0xf2f2f2));
+ m_highlightColumnColor = QColor(QRgb(0xf2f2f2));
+ m_lightStrength = 4.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 6.0f;
+ m_uniformColor = true;
+#elif defined(Q_OS_LINUX)
+ m_baseColor = QColor(QRgb(0x60a6e6));
+ m_heightColor = QColor(QRgb(0xfc5751));
+ m_depthColor = QColor(QRgb(0x92ca66));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xd6, 0xd6, 0xd6, 0x80);
+ m_gridLine = QColor(QRgb(0xe2e2e2));
+ m_highlightBarColor = QColor(QRgb(0xeba85f));
+ m_highlightRowColor = QColor(QRgb(0xfc5751));
+ m_highlightColumnColor = QColor(QRgb(0xfc5751));
+ m_lightStrength = 4.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 6.0f;
+ m_uniformColor = true;
+#elif defined(Q_OS_MAC)
+ m_baseColor = QColor(QRgb(0x60a6e6));
+ m_heightColor = QColor(QRgb(0xfc5751));
+ m_depthColor = QColor(QRgb(0x92ca66));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xd6, 0xd6, 0xd6, 0x80);
+ m_gridLine = QColor(QRgb(0xe2e2e2));
+ m_highlightBarColor = QColor(QRgb(0xeba85f));
+ m_highlightRowColor = QColor(QRgb(0xfc5751));
+ m_highlightColumnColor = QColor(QRgb(0xfc5751));
+ m_lightStrength = 4.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 6.0f;
+ m_uniformColor = true;
+#else
+ m_baseColor = QColor(QRgb(0x60a6e6));
+ m_heightColor = QColor(QRgb(0xfc5751));
+ m_depthColor = QColor(QRgb(0x92ca66));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xd6, 0xd6, 0xd6, 0x80);
+ m_gridLine = QColor(QRgb(0xe2e2e2));
+ m_highlightBarColor = QColor(QRgb(0xeba85f));
+ m_highlightRowColor = QColor(QRgb(0xfc5751));
+ m_highlightColumnColor = QColor(QRgb(0xfc5751));
+ m_lightStrength = 4.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 6.0f;
+ m_uniformColor = true;
+#endif
+ qDebug("ThemeSystem");
+ break;
+ }
+ case ThemeBlueCerulean: {
+ m_baseColor = QColor(QRgb(0xc7e85b));
+ m_heightColor = QColor(QRgb(0xee7392));
+ m_depthColor = QColor(QRgb(0x1cb54f));
+ m_backgroundColor = QColor(QRgb(0x056189));
+ m_windowColor = QColor(QRgb(0x101a31));
+ m_textColor = QColor(QRgb(0xffffff));
+ m_textBackgroundColor = QColor(0x05, 0x61, 0x89, 0x80);
+ m_gridLine = QColor(QRgb(0x84a2b0));
+ m_highlightBarColor = QColor(QRgb(0x5cbf9b));
+ m_highlightRowColor = QColor(QRgb(0x009fbf));
+ m_highlightColumnColor = QColor(QRgb(0x009fbf));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.2f;
+ m_highlightLightStrength = 10.0f;
+ m_uniformColor = true;
+ qDebug("ThemeBlueCerulean");
+ break;
+ }
+ case ThemeBlueIcy: {
+ m_baseColor = QRgb(0x3daeda);
+ m_heightColor = QRgb(0x2fa3b4);
+ m_depthColor = QColor(QRgb(0x2685bf));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x80);
+ m_gridLine = QColor(QRgb(0xe2e2e2));
+ m_highlightBarColor = QColor(QRgb(0x0c2673));
+ m_highlightRowColor = QColor(QRgb(0x5f3dba));
+ m_highlightColumnColor = QColor(QRgb(0x5f3dba));
+ m_lightStrength = 5.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 8.0f;
+ m_uniformColor = true;
+ qDebug("ThemeBlueIcy");
+ break;
+ }
+ case ThemeBlueNcs: {
+ m_baseColor = QColor(QRgb(0x1db0da));
+ m_heightColor = QColor(QRgb(0x398ca3));
+ m_depthColor = QColor(QRgb(0x1341a6));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0xff);
+ m_gridLine = QColor(QRgb(0xe2e2e2));
+ m_highlightBarColor = QColor(QRgb(0x88d41e));
+ m_highlightRowColor = QColor(QRgb(0xff8e1a));
+ m_highlightColumnColor = QColor(QRgb(0xff8e1a));
+ m_lightStrength = 4.0f;
+ m_ambientStrength = 0.2f;
+ m_highlightLightStrength = 6.0f;
+ m_uniformColor = true;
+ qDebug("ThemeBlueNcs");
+ break;
+ }
+ case ThemeBrownSand: {
+ m_baseColor = QColor(QRgb(0xb39b72));
+ m_heightColor = QColor(QRgb(0x494345));
+ m_depthColor = QColor(QRgb(0xb3b376));
+ m_backgroundColor = QColor(QRgb(0xf3ece0));
+ m_windowColor = QColor(QRgb(0xf3ece0));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xb5, 0xb0, 0xa7, 0x80);
+ m_gridLine = QColor(QRgb(0xd4cec3));
+ m_highlightBarColor = QColor(QRgb(0xc35660));
+ m_highlightRowColor = QColor(QRgb(0x536780));
+ m_highlightColumnColor = QColor(QRgb(0x536780));
+ m_lightStrength = 6.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 8.0f;
+ m_uniformColor = false;
+ qDebug("ThemeBrownSand");
+ break;
+ }
+ case ThemeDark: {
+ m_baseColor = QColor(QRgb(0x38ad6b)); // charts: series color 1
+ m_heightColor = QColor(QRgb(0xbf593e)); // charts: series color 5
+ m_depthColor = QColor(QRgb(0x3c84a7)); // charts: series color 2
+ m_backgroundColor = QColor(QRgb(0x2e303a)); // charts: background color 1
+ m_windowColor = QColor(QRgb(0x121218)); // charts: background color 2
+ m_textColor = QColor(QRgb(0xffffff)); // charts: label color
+ m_textBackgroundColor = QColor(0x86, 0x87, 0x8c, 0x80); // charts: axis line pen OR background color 2
+ m_gridLine = QColor(QRgb(0x86878c)); // charts: grid line color
+ m_highlightBarColor = QColor(QRgb(0xeb8817)); // charts: series color 3
+ m_highlightRowColor = QColor(QRgb(0x7b7f8c)); // charts: series color 4
+ m_highlightColumnColor = QColor(QRgb(0x7b7f8c)); // charts: series color 4
+ m_lightStrength = 6.0f;
+ m_ambientStrength = 0.2f;
+ m_highlightLightStrength = 8.0f;
+ m_uniformColor = false;
+ qDebug("ThemeDark");
+ break;
+ }
+ case ThemeHighContrast: {
+ m_baseColor = QColor(QRgb(0x202020));
+ m_heightColor = QColor(QRgb(0xff4a41));
+ m_depthColor = QColor(QRgb(0x596a74));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0x000000));
+ m_textColor = QColor(QRgb(0x181818));
+ m_textBackgroundColor = QColor(0xff, 0xff, 0xff, 0x80);
+ m_gridLine = QColor(QRgb(0x8c8c8c));
+ m_highlightBarColor = QColor(QRgb(0xffab03));
+ m_highlightRowColor = QColor(QRgb(0x038e9b));
+ m_highlightColumnColor = QColor(QRgb(0x038e9b));
+ m_lightStrength = 8.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 10.0f;
+ m_uniformColor = false;
+ qDebug("ThemeHighContrast");
+ break;
+ }
+ case ThemeLight: {
+ m_baseColor = QColor(QRgb(0x209fdf));
+ m_heightColor = QColor(QRgb(0xbf593e));
+ m_depthColor = QColor(QRgb(0x99ca53));
+ m_backgroundColor = QColor(QRgb(0xffffff));
+ m_windowColor = QColor(QRgb(0xffffff));
+ m_textColor = QColor(QRgb(0x404044));
+ m_textBackgroundColor = QColor(0xd6, 0xd6, 0xd6, 0x80);
+ m_gridLine = QColor(QRgb(0xe2e2e2));
+ m_highlightBarColor = QColor(QRgb(0xf6a625));
+ m_highlightRowColor = QColor(QRgb(0x6d5fd5));
+ m_highlightColumnColor = QColor(QRgb(0x6d5fd5));
+ m_lightStrength = 6.0f;
+ m_ambientStrength = 0.3f;
+ m_highlightLightStrength = 7.0f;
+ m_uniformColor = true;
+ qDebug("ThemeLight");
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/engine/theme_p.h b/src/datavis3d/engine/theme_p.h
new file mode 100644
index 00000000..d55e9a33
--- /dev/null
+++ b/src/datavis3d/engine/theme_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef THEME_P_H
+#define THEME_P_H
+
+#include "QtDataVis3D/qdatavis3dglobal.h"
+#include "QtDataVis3D/qdatavis3namespace.h"
+#include "q3dbars.h"
+
+class QColor;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Theme
+{
+public:
+ explicit Theme();
+ ~Theme();
+
+ void useTheme(ColorTheme theme);
+
+private:
+ friend class Q3DBars;
+ friend class Q3DBarsPrivate;
+ friend class Q3DMaps;
+ friend class Q3DMapsPrivate;
+ friend class Drawer;
+
+ QColor m_baseColor;
+ QColor m_heightColor;
+ QColor m_depthColor;
+ QColor m_backgroundColor;
+ QColor m_windowColor;
+ QColor m_textColor;
+ QColor m_textBackgroundColor;
+ QColor m_gridLine;
+ QColor m_highlightBarColor;
+ QColor m_highlightRowColor;
+ QColor m_highlightColumnColor;
+ float m_lightStrength;
+ float m_ambientStrength;
+ float m_highlightLightStrength;
+ bool m_uniformColor;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/global/global.pri b/src/datavis3d/global/global.pri
new file mode 100644
index 00000000..56cb9f8f
--- /dev/null
+++ b/src/datavis3d/global/global.pri
@@ -0,0 +1,5 @@
+INCLUDEPATH += $$PWD
+VPATH += $$PWD
+HEADERS += \
+ global/qdatavis3dglobal.h \
+ global/qdatavis3namespace.h
diff --git a/src/datavis3d/global/qdatavis3dglobal.h b/src/datavis3d/global/qdatavis3dglobal.h
new file mode 100644
index 00000000..528180b3
--- /dev/null
+++ b/src/datavis3d/global/qdatavis3dglobal.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of QtDataVis3D.
+**
+** $QT_BEGIN_LICENSE$
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVIS3DGLOBAL_H
+#define QVIS3DGLOBAL_H
+
+#include <qglobal.h>
+
+//#define ROTATE_ZOOM_SELECTION
+
+#define QTCOMMERCIALDATAVIS3D_VERSION_STR "0.0.1"
+/*
+ QTCOMMERCIALDATAVIS3D_VERSION is (major << 16) + (minor << 8) + patch.
+*/
+#define QTCOMMERCIALDATAVIS3D_VERSION 0x000001
+/*
+ can be used like #if (QTCOMMERCIALDATAVIS3D_VERSION >= QTCOMMERCIALDATAVIS3D_VERSION_CHECK(1, 1, 0))
+*/
+#define QTCOMMERCIALDATAVIS3D_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
+
+#if defined(QTCOMMERCIALDATAVIS3D_LIBRARY)
+# define QTCOMMERCIALDATAVIS3D_EXPORT Q_DECL_EXPORT
+#else
+# define QTCOMMERCIALDATAVIS3D_EXPORT Q_DECL_IMPORT
+#endif
+
+#if defined(BUILD_PRIVATE_UNIT_TESTS) && defined(QTCOMMERCIALDATAVIS3D_LIBRARY)
+# define QTCOMMERCIALDATAVIS3D_AUTOTEST_EXPORT Q_DECL_EXPORT
+#elif defined(BUILD_PRIVATE_UNIT_TESTS) && !defined(QTCOMMERCIALDATAVIS3D_LIBRARY)
+# define QTCOMMERCIALDATAVIS3D_AUTOTEST_EXPORT Q_DECL_IMPORT
+#else
+# define QTCOMMERCIALDATAVIS3D_AUTOTEST_EXPORT
+#endif
+
+#ifdef QTCOMMERCIALDATAVIS3D_STATICLIB
+# undef QTCOMMERCIALDATAVIS3D_EXPORT
+# undef QTCOMMERCIALDATAVIS3D_AUTOTEST_EXPORT
+# define QTCOMMERCIALDATAVIS3D_EXPORT
+# define QTCOMMERCIALDATAVIS3D_AUTOTEST_EXPORT
+#endif
+
+#define QTCOMMERCIALDATAVIS3D_NAMESPACE QtDataVis3D
+
+#ifdef QTCOMMERCIALDATAVIS3D_NAMESPACE
+# define QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE namespace QTCOMMERCIALDATAVIS3D_NAMESPACE {
+# define QTCOMMERCIALDATAVIS3D_END_NAMESPACE }
+# define QTCOMMERCIALDATAVIS3D_USE_NAMESPACE using namespace QTCOMMERCIALDATAVIS3D_NAMESPACE;
+#else
+# define QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+# define QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+# define QTCOMMERCIALDATAVIS3D_USE_NAMESPACE
+#endif
+
+#if defined(DEVELOPMENT_BUILD) && !defined(QT_NO_DEBUG)
+#include <stdarg.h>
+#include <QDebug>
+
+#define CHART_DEBUG chartDebug(3,__LINE__,__FILE__,__FUNCTION__)
+
+static inline QDebug chartDebug(int numargs,...)
+{
+ va_list valist;
+ va_start(valist, numargs);
+ //for( int i = 0 ; i < numargs; i++ )
+ int line = va_arg(valist, int);
+ char *file = va_arg(valist, char *);
+ char *function = va_arg(valist, char *);
+ va_end(valist);
+ return qDebug() << QString().append(function).append("(").append(file).append(":%1)").arg(line);
+}
+#endif
+
+#endif // QVIS3DGLOBAL_H
diff --git a/src/datavis3d/global/qdatavis3namespace.h b/src/datavis3d/global/qdatavis3namespace.h
new file mode 100644
index 00000000..b75bce29
--- /dev/null
+++ b/src/datavis3d/global/qdatavis3namespace.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QVIS3DNAMESPACE_H
+#define QVIS3DNAMESPACE_H
+
+#include "qdatavis3dglobal.h"
+#include <QOpenGLFunctions>
+#include <QVector3D>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+// Constants used in several files
+const GLfloat m_pi = 3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679f;
+// Compensation for z position; move all objects to positive z, as shader can't handle negative values correctly
+const GLfloat zComp = 10.0f;
+// Default light position. To have shadows working correctly, light should be as far as camera, or a bit further
+// y position is added to the minimum height (or can be thought to be that much above or below the camera)
+const QVector3D defaultLightPos = QVector3D(0.0f, 0.5f, zComp);
+const GLfloat defaultRatio = 1.0f / 1.6f; // default aspect ratio 16:10
+
+// Enums used in several files
+enum BarStyle {
+ Bars = 0,
+ Pyramids,
+ Cones,
+ Cylinders,
+ Spheres
+};
+
+enum CameraPreset {
+ PresetFrontLow = 0,
+ PresetFront,
+ PresetFrontHigh,
+ PresetLeftLow,
+ PresetLeft,
+ PresetLeftHigh,
+ PresetRightLow,
+ PresetRight,
+ PresetRightHigh,
+ PresetBehindLow,
+ PresetBehind,
+ PresetBehindHigh,
+ PresetIsometricLeft,
+ PresetIsometricLeftHigh,
+ PresetIsometricRight,
+ PresetIsometricRightHigh,
+ PresetDirectlyAbove,
+ PresetDirectlyAboveCW45,
+ PresetDirectlyAboveCCW45
+};
+
+enum ColorTheme {
+ ThemeSystem = 0,
+ ThemeBlueCerulean,
+ ThemeBlueIcy,
+ ThemeBlueNcs,
+ ThemeBrownSand,
+ ThemeDark,
+ ThemeHighContrast,
+ ThemeLight
+};
+
+enum LabelTransparency {
+ TransparencyNone = 0, // Full solid, using colors from theme
+ TransparencyFromTheme, // Use colors and transparencies from theme
+ TransparencyNoBackground // Draw just text on transparent background
+};
+
+// TODO: Will this be used in other vis types than q3dbars?
+enum SelectionMode {
+ ModeNone = 0,
+ ModeBar,
+ ModeBarAndRow,
+ ModeBarAndColumn,
+ ModeBarRowAndColumn,
+ ModeZoomRow,
+ ModeZoomColumn
+};
+
+// TODO: Should this be moved to Q3DBarsPrivate? Not for use via API directly?
+enum LabelPosition {
+ LabelBelow = 0,
+ LabelLow,
+ LabelMid,
+ LabelHigh,
+ LabelOver,
+ LabelBottom, // Absolute positions from here onward, used for axes (QDataItem is ignored)
+ LabelTop,
+ LabelLeft,
+ LabelRight
+};
+
+enum ShadowQuality {
+ ShadowNone = 0,
+ ShadowLow = 1,
+ ShadowMedium = 3,
+ ShadowHigh = 5
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/camerahelper.cpp b/src/datavis3d/utils/camerahelper.cpp
new file mode 100644
index 00000000..2e868cac
--- /dev/null
+++ b/src/datavis3d/utils/camerahelper.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "camerahelper_p.h"
+
+#include <qmath.h>
+#include <QMatrix4x4>
+#include <QVector3D>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+// Initial camera position
+QVector3D m_position = QVector3D(0, 0.25, 3);
+QVector3D m_target = QVector3D(0, 0, 0);
+QVector3D m_up = QVector3D(0, 1, 0);
+
+QPoint m_previousMousePos(0, 0);
+
+GLfloat m_xRotation = 0;
+GLfloat m_yRotation = 0;
+GLfloat m_defaultXRotation = 0;
+GLfloat m_defaultYRotation = 0;
+
+GLfloat m_rotationSpeed = 100;
+
+// FUNCTIONS
+void CameraHelper::setRotationSpeed(int speed)
+{
+ // increase for faster rotation
+ m_rotationSpeed = speed;
+}
+
+void CameraHelper::setCameraRotation(const QPointF &rotation)
+{
+ m_xRotation = rotation.x();
+ m_defaultXRotation = m_xRotation;
+ m_yRotation = rotation.y();
+ m_defaultYRotation = m_yRotation;
+}
+
+void CameraHelper::setDefaultCameraOrientation(const QVector3D &defaultPosition,
+ const QVector3D &defaultTarget,
+ const QVector3D &defaultUp)
+{
+ m_position = defaultPosition;
+ m_target = defaultTarget;
+ m_up = defaultUp;
+}
+
+QMatrix4x4 CameraHelper::calculateViewMatrix(const QPoint &mousePos, int zoom,
+ int screenWidth, int screenHeight)
+{
+ QMatrix4x4 viewMatrix;
+
+ // Calculate mouse movement since last frame
+ GLfloat mouseMoveX = GLfloat(m_previousMousePos.x() - mousePos.x())
+ / (screenWidth / m_rotationSpeed);
+ GLfloat mouseMoveY = GLfloat(m_previousMousePos.y() - mousePos.y())
+ / (screenHeight / m_rotationSpeed);
+ // Apply to rotations
+ m_xRotation -= mouseMoveX;
+ m_yRotation -= mouseMoveY;
+ // Reset at 360 in x and limit to 0...90 in y
+ if (qFabs(m_xRotation) >= 360)
+ m_xRotation = 0;
+ if (m_yRotation >= 90)
+ m_yRotation = 90;
+ else if (m_yRotation <= 0)
+ m_yRotation = 0;
+
+ // Apply to view matrix
+ viewMatrix.lookAt(m_position, m_target, m_up);
+ // Compensate for translation (if m_target is off origin)
+ viewMatrix.translate(m_target.x(), m_target.y(), m_target.z());
+ // Apply rotations
+ // Handle x and z rotation when y -angle is other than 0
+ viewMatrix.rotate(m_xRotation, 0, cos(m_yRotation * m_pi / 180.0f),
+ sin(m_yRotation * m_pi / 180.0f));
+ // y rotation is always "clean"
+ viewMatrix.rotate(m_yRotation, 1.0f, 0.0f, 0.0f);
+ // handle zoom by scaling
+ viewMatrix.scale((GLfloat)zoom / 100.0f);
+ // Compensate for translation (if m_target is off origin)
+ viewMatrix.translate(-m_target.x(), -m_target.y(), -m_target.z());
+ //qDebug() << m_xRotation << m_yRotation;
+
+ //qDebug() << "sin(m_yRotation)" << sin(m_yRotation*m_pi/180);
+ //qDebug() << "asin(m_yRotation)" << asin(m_yRotation*m_pi/180);
+ //qDebug() << "cos(m_yRotation)" << cos(m_yRotation*m_pi/180);
+ //qDebug() << "tan(m_yRotation)" << tan(m_yRotation*m_pi/180);
+
+ m_previousMousePos = mousePos;
+ return viewMatrix;
+}
+
+QVector3D CameraHelper::calculateLightPosition(const QVector3D &lightPosition,
+ GLfloat fixedRotation, GLfloat distanceModifier)
+{
+ // Move light with camera
+ QVector3D newLightPosition;
+ GLfloat radiusFactor = lightPosition.z() * (1.5f + distanceModifier); // for making sure light is outside the scene at its lowest point
+ GLfloat xAngle;
+ GLfloat yAngle;
+ if (!fixedRotation) {
+ xAngle = m_xRotation * m_pi / 180.0f;
+ yAngle = m_yRotation * m_pi / 180.0f;
+ } else {
+ xAngle = fixedRotation * m_pi / 180.0f;
+ yAngle = 0;
+ }
+ GLfloat radius = (radiusFactor + lightPosition.y()); // set radius to match the highest height of the light
+ GLfloat zPos = radius * cos(xAngle) * cos(yAngle);
+ GLfloat xPos = radius * sin(xAngle) * cos(yAngle);
+ GLfloat yPos = (radiusFactor + lightPosition.y()) * sin(yAngle);
+ // Keep light in the set position in relation to camera
+ // TODO: Does not work perfectly yet; Light seems wrong when viewing scene from sides (or isometrically)
+ newLightPosition = QVector3D(-xPos + lightPosition.x(),
+ yPos + lightPosition.y(),
+ zPos + lightPosition.z());
+ //qDebug() << newLightPosition << xAngle << yAngle << fixedRotation;
+ return newLightPosition;
+}
+
+void CameraHelper::updateMousePos(const QPoint &mousePos)
+{
+ m_previousMousePos = mousePos;
+ // if mouse position is set to (0, 0), reset rotations
+ if (QPoint(0, 0) == mousePos) {
+ m_xRotation = m_defaultXRotation;
+ m_yRotation = m_defaultYRotation;
+ }
+}
+
+QPointF CameraHelper::getCameraRotations()
+{
+ QPointF rotations(m_xRotation, m_yRotation);
+ return rotations;
+}
+
+void CameraHelper::setCameraPreset(CameraPreset preset)
+{
+ switch (preset) {
+ case PresetFrontLow: {
+ qDebug("PresetFrontLow");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 0.0f));
+ break;
+ }
+ case PresetFront: {
+ qDebug("PresetFront");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 22.5f));
+ break;
+ }
+ case PresetFrontHigh: {
+ qDebug("PresetFrontHigh");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 45.0f));
+ break;
+ }
+ case PresetLeftLow: {
+ qDebug("PresetLeftLow");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 0.0f));
+ break;
+ }
+ case PresetLeft: {
+ qDebug("PresetLeft");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 22.5f));
+ break;
+ }
+ case PresetLeftHigh: {
+ qDebug("PresetLeftHigh");
+ CameraHelper::setCameraRotation(QPointF(90.0f, 45.0f));
+ break;
+ }
+ case PresetRightLow: {
+ qDebug("PresetRightLow");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 0.0f));
+ break;
+ }
+ case PresetRight: {
+ qDebug("PresetRight");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 22.5f));
+ break;
+ }
+ case PresetRightHigh: {
+ qDebug("PresetRightHigh");
+ CameraHelper::setCameraRotation(QPointF(-90.0f, 45.0f));
+ break;
+ }
+ case PresetBehindLow: {
+ qDebug("PresetBehindLow");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 0.0f));
+ break;
+ }
+ case PresetBehind: {
+ qDebug("PresetBehind");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 22.5f));
+ break;
+ }
+ case PresetBehindHigh: {
+ qDebug("PresetBehindHigh");
+ CameraHelper::setCameraRotation(QPointF(180.0f, 45.0f));
+ break;
+ }
+ case PresetIsometricLeft: {
+ qDebug("PresetIsometricLeft");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 22.5f));
+ break;
+ }
+ case PresetIsometricLeftHigh: {
+ qDebug("PresetIsometricLeftHigh");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 45.0f));
+ break;
+ }
+ case PresetIsometricRight: {
+ qDebug("PresetIsometricRight");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 22.5f));
+ break;
+ }
+ case PresetIsometricRightHigh: {
+ qDebug("PresetIsometricRightHigh");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 45.0f));
+ break;
+ }
+ case PresetDirectlyAbove: {
+ qDebug("PresetDirectlyAbove");
+ CameraHelper::setCameraRotation(QPointF(0.0f, 90.0f));
+ break;
+ }
+ case PresetDirectlyAboveCW45: {
+ qDebug("PresetDirectlyAboveCW45");
+ CameraHelper::setCameraRotation(QPointF(-45.0f, 90.0f));
+ break;
+ }
+ case PresetDirectlyAboveCCW45: {
+ qDebug("PresetDirectlyAboveCCW45");
+ CameraHelper::setCameraRotation(QPointF(45.0f, 90.0f));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/camerahelper_p.h b/src/datavis3d/utils/camerahelper_p.h
new file mode 100644
index 00000000..68e7e5a2
--- /dev/null
+++ b/src/datavis3d/utils/camerahelper_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CAMERAPOSITIONER_P_H
+#define CAMERAPOSITIONER_P_H
+
+#include "qdatavis3dglobal.h"
+#include "qdatavis3namespace.h"
+#include "q3dbars.h"
+
+class QMatrix4x4;
+class QVector3D;
+class QPoint;
+class QPointF;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class CameraHelper
+{
+ public:
+ // How fast camera rotates when mouse is dragged. Default is 100.
+ static void setRotationSpeed(int speed);
+ // Set camera rotation in degrees
+ static void setCameraRotation(const QPointF &rotation);
+ // Get camera rotations
+ static QPointF getCameraRotations();
+ // Set default camera orientation. Position's x and y should be 0.
+ static void setDefaultCameraOrientation(const QVector3D &defaultPosition,
+ const QVector3D &defaultTarget,
+ const QVector3D &defaultUp);
+ // Calculate view matrix based on rotation and zoom
+ static QMatrix4x4 calculateViewMatrix(const QPoint &mousePos, int zoom,
+ int screenWidth, int screenHeight);
+ // Calcluate light position based on rotation. Call after calling calculateViewMatrix to get
+ // up-to-date position
+ static QVector3D calculateLightPosition(const QVector3D &lightPosition,
+ GLfloat fixedRotation = 0.0f,
+ GLfloat distanceModifier = 0.0f);
+ static void updateMousePos(const QPoint &mousePos);
+ static void setCameraPreset(CameraPreset preset);
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/meshloader.cpp b/src/datavis3d/utils/meshloader.cpp
new file mode 100644
index 00000000..0e818a92
--- /dev/null
+++ b/src/datavis3d/utils/meshloader.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "meshloader_p.h"
+
+#include <QFile>
+#include <QStringList>
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+QString slashTag = QStringLiteral("/");
+
+bool MeshLoader::loadOBJ(const QString &path,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals)
+{
+ //qDebug() << "Loading OBJ file" << path;
+
+ QVector<unsigned int> vertexIndices, uvIndices, normalIndices;
+ QVector<QVector3D> temp_vertices;
+ QVector<QVector2D> temp_uvs;
+ QVector<QVector3D> temp_normals;
+
+ QFile file(path);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning("Cannot open the file");
+ return false;
+ }
+
+ QTextStream textIn(&file);
+ while (!textIn.atEnd()) {
+ QString line = textIn.readLine();
+ QStringList lineContents = line.split(QStringLiteral(" "));
+ if (!lineContents.at(0).compare(QStringLiteral("v"))) {
+ QVector3D vertex;
+ vertex.setX(lineContents.at(1).toFloat());
+ vertex.setY(lineContents.at(2).toFloat());
+ vertex.setZ(lineContents.at(3).toFloat());
+ temp_vertices.append(vertex);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("vt"))) {
+ QVector2D uv;
+ uv.setX(lineContents.at(1).toFloat());
+ uv.setY(lineContents.at(2).toFloat()); // invert this if using DDS textures
+ temp_uvs.append(uv);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("vn"))) {
+ QVector3D normal;
+ normal.setX(lineContents.at(1).toFloat());
+ normal.setY(lineContents.at(2).toFloat());
+ normal.setZ(lineContents.at(3).toFloat());
+ temp_normals.append(normal);
+ }
+ else if (!lineContents.at(0).compare(QStringLiteral("f"))) {
+ unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
+ QStringList set1 = lineContents.at(1).split(slashTag);
+ QStringList set2 = lineContents.at(2).split(slashTag);
+ QStringList set3 = lineContents.at(3).split(slashTag);
+ vertexIndex[0] = set1.at(0).toUInt();
+ vertexIndex[1] = set2.at(0).toUInt();
+ vertexIndex[2] = set3.at(0).toUInt();
+ uvIndex[0] = set1.at(1).toUInt();
+ uvIndex[1] = set2.at(1).toUInt();
+ uvIndex[2] = set3.at(1).toUInt();
+ normalIndex[0] = set1.at(2).toUInt();
+ normalIndex[1] = set2.at(2).toUInt();
+ normalIndex[2] = set3.at(2).toUInt();
+ vertexIndices.append(vertexIndex[0]);
+ vertexIndices.append(vertexIndex[1]);
+ vertexIndices.append(vertexIndex[2]);
+ uvIndices.append(uvIndex[0]);
+ uvIndices.append(uvIndex[1]);
+ uvIndices.append(uvIndex[2]);
+ normalIndices.append(normalIndex[0]);
+ normalIndices.append(normalIndex[1]);
+ normalIndices.append(normalIndex[2]);
+ }
+ else {
+ //qWarning("Line did not contain usable data");
+ }
+ }
+
+ // For each vertex of each triangle
+ for (int i = 0; i < vertexIndices.size(); i++) {
+ // Get the indices of its attributes
+ unsigned int vertexIndex = vertexIndices[i];
+ unsigned int uvIndex = uvIndices[i];
+ unsigned int normalIndex = normalIndices[i];
+
+ // Get the attributes thanks to the index
+ QVector3D vertex = temp_vertices[vertexIndex - 1];
+ QVector2D uv = temp_uvs[uvIndex - 1];
+ QVector3D normal = temp_normals[normalIndex - 1];
+
+ // Put the attributes in buffers
+ out_vertices.append(vertex);
+ out_uvs.append(uv);
+ out_normals.append(normal);
+ }
+
+ return true;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/meshloader_p.h b/src/datavis3d/utils/meshloader_p.h
new file mode 100644
index 00000000..514ae5c6
--- /dev/null
+++ b/src/datavis3d/utils/meshloader_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef MESHLOADER_P_H
+#define MESHLOADER_P_H
+
+#include "qdatavis3dglobal.h"
+
+class QVector2D;
+class QVector3D;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class MeshLoader
+{
+ public:
+ static bool loadOBJ(const QString &path,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals);
+ // TODO: add loaders for other formats?
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/objecthelper.cpp b/src/datavis3d/utils/objecthelper.cpp
new file mode 100644
index 00000000..6659a187
--- /dev/null
+++ b/src/datavis3d/utils/objecthelper.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "meshloader_p.h"
+#include "vertexindexer_p.h"
+#include "objecthelper_p.h"
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+ObjectHelper::ObjectHelper(const QString &objectFile)
+ : m_objectFile(objectFile),
+ m_vertexbuffer(0),
+ m_normalbuffer(0),
+ m_uvbuffer(0),
+ m_elementbuffer(0),
+ m_indexCount(0),
+ m_meshDataLoaded(false)
+{
+ initializeOpenGLFunctions();
+}
+
+ObjectHelper::~ObjectHelper()
+{
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+}
+
+void ObjectHelper::setObjectFile(const QString &objectFile)
+{
+ m_objectFile = objectFile;
+}
+
+void ObjectHelper::load()
+{
+ if (m_meshDataLoaded) {
+ // Delete old data
+ glDeleteBuffers(1, &m_vertexbuffer);
+ glDeleteBuffers(1, &m_uvbuffer);
+ glDeleteBuffers(1, &m_normalbuffer);
+ glDeleteBuffers(1, &m_elementbuffer);
+ }
+ QVector<QVector3D> vertices;
+ QVector<QVector2D> uvs;
+ QVector<QVector3D> normals;
+ bool loadOk = MeshLoader::loadOBJ(m_objectFile, vertices, uvs, normals);
+ if (!loadOk)
+ qFatal("loading failed");
+
+ //qDebug() << "vertex count" << vertices.size();;
+
+ // Index vertices
+ QVector<unsigned short> indices;
+ QVector<QVector3D> indexed_vertices;
+ QVector<QVector2D> indexed_uvs;
+ QVector<QVector3D> indexed_normals;
+ VertexIndexer::indexVBO(vertices, uvs, normals, indices, indexed_vertices, indexed_uvs,
+ indexed_normals);
+
+ m_indexCount = indices.size();
+ //qDebug() << "index count" << m_indexCount;
+
+ glGenBuffers(1, &m_vertexbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_vertexbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_vertices.size() * sizeof(QVector3D),
+ &indexed_vertices.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_normalbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_normalbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_normals.size() * sizeof(QVector3D),
+ &indexed_normals.at(0),
+ GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_uvbuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_uvbuffer);
+ glBufferData(GL_ARRAY_BUFFER, indexed_uvs.size() * sizeof(QVector2D),
+ &indexed_uvs.at(0), GL_STATIC_DRAW);
+
+ glGenBuffers(1, &m_elementbuffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementbuffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned short),
+ &indices.at(0), GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ m_meshDataLoaded = true;
+}
+
+GLuint ObjectHelper::vertexBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_vertexbuffer;
+}
+
+GLuint ObjectHelper::normalBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_normalbuffer;
+}
+
+GLuint ObjectHelper::uvBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_uvbuffer;
+}
+
+GLuint ObjectHelper::elementBuf()
+{
+ if (!m_meshDataLoaded)
+ qFatal("No loaded object");
+ return m_elementbuffer;
+}
+
+GLuint ObjectHelper::indexCount()
+{
+ return m_indexCount;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/objecthelper_p.h b/src/datavis3d/utils/objecthelper_p.h
new file mode 100644
index 00000000..f3e342ba
--- /dev/null
+++ b/src/datavis3d/utils/objecthelper_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef OBJECTHELPER_P_H
+#define OBJECTHELPER_P_H
+
+#include "qdatavis3dglobal.h"
+#include <QOpenGLFunctions>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class ObjectHelper: protected QOpenGLFunctions
+{
+ public:
+ ObjectHelper(const QString &objectFile = QString());
+ ~ObjectHelper();
+
+ void setObjectFile(const QString &objectFile);
+
+ void load();
+
+ GLuint vertexBuf();
+ GLuint normalBuf();
+ GLuint uvBuf();
+ GLuint elementBuf();
+ GLuint indexCount();
+
+ private:
+ QString m_objectFile;
+
+ GLuint m_vertexbuffer;
+ GLuint m_normalbuffer;
+ GLuint m_uvbuffer;
+ GLuint m_elementbuffer;
+
+ GLuint m_indexCount;
+
+ GLboolean m_meshDataLoaded;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/shaderhelper.cpp b/src/datavis3d/utils/shaderhelper.cpp
new file mode 100644
index 00000000..a66b6a00
--- /dev/null
+++ b/src/datavis3d/utils/shaderhelper.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "shaderhelper_p.h"
+
+#include <QOpenGLShader>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+ShaderHelper::ShaderHelper(QObject *parent,
+ const QString &vertexShader,
+ const QString &fragmentShader,
+ const QString &texture,
+ const QString &depthTexture)
+ : m_caller(parent),
+ m_program(0),
+ m_vertexShaderFile(vertexShader),
+ m_fragmentShaderFile(fragmentShader),
+ m_textureFile(texture),
+ m_depthTextureFile(depthTexture)
+{
+}
+
+ShaderHelper::~ShaderHelper()
+{
+ delete m_program;
+}
+
+void ShaderHelper::setShaders(const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ m_vertexShaderFile = vertexShader;
+ m_fragmentShaderFile = fragmentShader;
+}
+
+void ShaderHelper::setTextures(const QString &texture,
+ const QString &depthTexture)
+{
+ m_textureFile = texture;
+ m_depthTextureFile = depthTexture;
+}
+
+void ShaderHelper::initialize()
+{
+ if (m_program)
+ delete m_program;
+ m_program = new QOpenGLShaderProgram(m_caller);
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, m_vertexShaderFile))
+ qFatal("Compiling Vertex shader failed");
+ if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, m_fragmentShaderFile))
+ qFatal("Compiling Fragment shader failed");
+ m_program->link();
+
+ m_positionAttr = m_program->attributeLocation("vertexPosition_mdl");
+ m_normalAttr = m_program->attributeLocation("vertexNormal_mdl");
+ m_uvAttr = m_program->attributeLocation("vertexUV");
+
+ m_mvpMatrixUniform = m_program->uniformLocation("MVP");
+ m_viewMatrixUniform = m_program->uniformLocation("V");
+ m_modelMatrixUniform = m_program->uniformLocation("M");
+ m_invTransModelMatrixUniform = m_program->uniformLocation("itM");
+ m_depthMatrixUniform = m_program->uniformLocation("depthMVP");
+ m_lightPositionUniform = m_program->uniformLocation("lightPosition_wrld");
+ m_lightStrengthUniform = m_program->uniformLocation("lightStrength");
+ m_ambientStrengthUniform = m_program->uniformLocation("ambientStrength");
+ m_shadowQualityUniform = m_program->uniformLocation("shadowQuality");
+ m_colorUniform = m_program->uniformLocation("color_mdl");
+ m_textureUniform = m_program->uniformLocation("textureSampler");
+ m_shadowUniform = m_program->uniformLocation("shadowMap");
+
+ m_initialized = true;
+}
+
+void ShaderHelper::bind()
+{
+ m_program->bind();
+}
+
+void ShaderHelper::release()
+{
+ m_program->release();
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QVector3D &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QVector4D &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, const QMatrix4x4 &value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, GLfloat value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+void ShaderHelper::setUniformValue(GLuint uniform, GLint value)
+{
+ m_program->setUniformValue(uniform, value);
+}
+
+GLuint ShaderHelper::MVP()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_mvpMatrixUniform;
+}
+
+GLuint ShaderHelper::view()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_viewMatrixUniform;
+}
+
+GLuint ShaderHelper::model()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_modelMatrixUniform;
+}
+
+GLuint ShaderHelper::nModel()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_invTransModelMatrixUniform;
+}
+
+GLuint ShaderHelper::depth()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_depthMatrixUniform;
+}
+
+GLuint ShaderHelper::lightP()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_lightPositionUniform;
+}
+
+GLuint ShaderHelper::lightS()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_lightStrengthUniform;
+}
+
+GLuint ShaderHelper::ambientS()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_ambientStrengthUniform;
+}
+
+GLuint ShaderHelper::shadowQ()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_shadowQualityUniform;
+}
+
+GLuint ShaderHelper::color()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_colorUniform;
+}
+
+GLuint ShaderHelper::texture()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_textureUniform;
+}
+
+GLuint ShaderHelper::shadow()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_shadowUniform;
+}
+
+GLuint ShaderHelper::posAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_positionAttr;
+}
+
+GLuint ShaderHelper::uvAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_uvAttr;
+}
+
+GLuint ShaderHelper::normalAtt()
+{
+ if (!m_initialized)
+ qFatal("Shader not initialized");
+ return m_normalAttr;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/shaderhelper_p.h b/src/datavis3d/utils/shaderhelper_p.h
new file mode 100644
index 00000000..83e8b981
--- /dev/null
+++ b/src/datavis3d/utils/shaderhelper_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SHADERHELPER_P_H
+#define SHADERHELPER_P_H
+
+#include "qdatavis3dglobal.h"
+#include <QOpenGLFunctions>
+
+class QOpenGLShaderProgram;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class ShaderHelper
+{
+ public:
+ ShaderHelper(QObject *parent,
+ const QString &vertexShader = QString(),
+ const QString &fragmentShader = QString(),
+ const QString &texture = QString(),
+ const QString &depthTexture = QString());
+ ~ShaderHelper();
+
+ void setShaders(const QString &vertexShader, const QString &fragmentShader);
+ void setTextures(const QString &texture, const QString &depthTexture);
+
+ void initialize();
+ void bind();
+ void release();
+ void setUniformValue(GLuint uniform, const QVector3D &value);
+ void setUniformValue(GLuint uniform, const QVector4D &value);
+ void setUniformValue(GLuint uniform, const QMatrix4x4 &value);
+ void setUniformValue(GLuint uniform, GLfloat value);
+ void setUniformValue(GLuint uniform, GLint value);
+
+ GLuint MVP();
+ GLuint view();
+ GLuint model();
+ GLuint nModel();
+ GLuint depth();
+ GLuint lightP();
+ GLuint lightS();
+ GLuint ambientS();
+ GLuint shadowQ();
+ GLuint color();
+ GLuint texture();
+ GLuint shadow();
+
+ GLuint posAtt();
+ GLuint uvAtt();
+ GLuint normalAtt();
+
+ private:
+ QObject *m_caller;
+ QOpenGLShaderProgram *m_program;
+
+ QString m_vertexShaderFile;
+ QString m_fragmentShaderFile;
+
+ QString m_textureFile;
+ QString m_depthTextureFile;
+
+ GLuint m_positionAttr;
+ GLuint m_uvAttr;
+ GLuint m_normalAttr;
+
+ GLuint m_colorUniform;
+ GLuint m_viewMatrixUniform;
+ GLuint m_modelMatrixUniform;
+ GLuint m_invTransModelMatrixUniform;
+ GLuint m_depthMatrixUniform;
+ GLuint m_mvpMatrixUniform;
+ GLuint m_lightPositionUniform;
+ GLuint m_lightStrengthUniform;
+ GLuint m_ambientStrengthUniform;
+ GLuint m_shadowQualityUniform;
+ GLuint m_textureUniform;
+ GLuint m_shadowUniform;
+
+ GLboolean m_initialized;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/texturehelper.cpp b/src/datavis3d/utils/texturehelper.cpp
new file mode 100644
index 00000000..c0083b15
--- /dev/null
+++ b/src/datavis3d/utils/texturehelper.cpp
@@ -0,0 +1,358 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "texturehelper_p.h"
+
+#include <QImage>
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+TextureHelper::TextureHelper()
+{
+ initializeOpenGLFunctions();
+}
+
+TextureHelper::~TextureHelper()
+{
+}
+
+GLuint TextureHelper::create2DTexture(const QImage &image, bool useTrilinearFiltering, bool convert)
+{
+ if (image.isNull())
+ return 0;
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ if (convert) {
+ QImage glTexture = convertToGLFormat(image);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glTexture.width(), glTexture.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, glTexture.bits());
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
+ }
+ if (useTrilinearFiltering) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ } else {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return textureId;
+}
+
+GLuint TextureHelper::createCubeMapTexture(const QImage &image, bool useTrilinearFiltering)
+{
+ if (image.isNull())
+ return 0;
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);
+ QImage glTexture = convertToGLFormat(image);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP, 0, GL_RGBA, glTexture.width(), glTexture.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, glTexture.bits());
+ if (useTrilinearFiltering) {
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ } else {
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+ return textureId;
+}
+
+GLuint TextureHelper::createSelectionBuffer(const QSize &size, GLuint &texture,
+ GLuint &depthTexture)
+{
+ GLuint framebuffer;
+
+ // Create frame buffer
+ glGenFramebuffers(1, &framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+
+ // Create texture for the selection buffer
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB,
+ GL_UNSIGNED_BYTE, NULL);
+
+ // Create texture object for the depth buffer
+ glGenTextures(1, &depthTexture);
+ glBindTexture(GL_TEXTURE_2D, depthTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, size.width(), size.height(),
+ 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Attach texture to color attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
+ // Attach texture to depth attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return framebuffer;
+}
+
+GLuint TextureHelper::createSelectionTexture(const QSize &size, GLuint &frameBuffer,
+ GLuint &depthBuffer)
+{
+ GLuint textureid;
+
+ // Create texture for the selection buffer
+ glGenTextures(1, &textureid);
+ glBindTexture(GL_TEXTURE_2D, textureid);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size.width(), size.height(), 0, GL_RGB,
+ GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Create render buffer
+ glGenRenderbuffers(1, &depthBuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height());
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ // Create frame buffer
+ glGenFramebuffers(1, &frameBuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
+
+ // Attach texture to color attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureid, 0);
+ // Attach renderbuffer to depth attachment
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return textureid;
+}
+
+GLuint TextureHelper::createDepthTexture(const QSize &size, GLuint &frameBuffer, GLuint textureSize)
+{
+ GLuint depthtextureid;
+
+ // Create depth texture for the shadow mapping
+ glGenTextures(1, &depthtextureid);
+ glBindTexture(GL_TEXTURE_2D, depthtextureid);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ // Use the following line if using shader's version 2 of shadowing, comment out if not
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, size.width() * textureSize,
+ size.height() * textureSize, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ // Create frame buffer
+ glGenFramebuffers(1, &frameBuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
+
+ // Attach texture to depth attachment
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthtextureid, 0);
+
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+
+ // Verify that the frame buffer is complete
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ qCritical() << "Frame buffer creation failed" << status;
+ return 0;
+ }
+
+ // Restore the default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return depthtextureid;
+}
+
+void TextureHelper::deleteTexture(const GLuint *texture)
+{
+ glDeleteTextures(1, texture);
+}
+
+QImage TextureHelper::convertToGLFormat(const QImage &srcImage)
+{
+ QImage res(srcImage.size(), QImage::Format_ARGB32);
+ convertToGLFormatHelper(res, srcImage.convertToFormat(QImage::Format_ARGB32), GL_RGBA);
+ return res;
+}
+
+void TextureHelper::convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage,
+ GLenum texture_format)
+{
+ Q_ASSERT(dstImage.depth() == 32);
+ Q_ASSERT(srcImage.depth() == 32);
+
+ if (dstImage.size() != srcImage.size()) {
+ int target_width = dstImage.width();
+ int target_height = dstImage.height();
+ qreal sx = target_width / qreal(srcImage.width());
+ qreal sy = target_height / qreal(srcImage.height());
+
+ quint32 *dest = (quint32 *) dstImage.scanLine(0); // NB! avoid detach here
+ uchar *srcPixels = (uchar *) srcImage.scanLine(srcImage.height() - 1);
+ int sbpl = srcImage.bytesPerLine();
+ int dbpl = dstImage.bytesPerLine();
+
+ int ix = int(0x00010000 / sx);
+ int iy = int(0x00010000 / sy);
+
+ quint32 basex = int(0.5 * ix);
+ quint32 srcy = int(0.5 * iy);
+
+ // scale, swizzle and mirror in one loop
+ while (target_height--) {
+ const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl);
+ int srcx = basex;
+ for (int x=0; x<target_width; ++x) {
+ dest[x] = qt_gl_convertToGLFormatHelper(src[srcx >> 16], texture_format);
+ srcx += ix;
+ }
+ dest = (quint32 *)(((uchar *) dest) + dbpl);
+ srcy += iy;
+ }
+ } else {
+ const int width = srcImage.width();
+ const int height = srcImage.height();
+ const uint *p = (const uint*) srcImage.scanLine(srcImage.height() - 1);
+ uint *q = (uint*) dstImage.scanLine(0);
+
+ if (texture_format == GL_BGRA) {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ // mirror + swizzle
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 24) & 0xff000000)
+ | ((*p >> 24) & 0x000000ff)
+ | ((*p << 8) & 0x00ff0000)
+ | ((*p >> 8) & 0x0000ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ const uint bytesPerLine = srcImage.bytesPerLine();
+ for (int i=0; i < height; ++i) {
+ memcpy(q, p, bytesPerLine);
+ q += width;
+ p -= width;
+ }
+ }
+ } else {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = (*p << 8) | ((*p >> 24) & 0xff);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ } else {
+ for (int i=0; i < height; ++i) {
+ const uint *end = p + width;
+ while (p < end) {
+ *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ p++;
+ q++;
+ }
+ p -= 2 * width;
+ }
+ }
+ }
+ }
+}
+
+QRgb TextureHelper::qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format)
+{
+ if (texture_format == GL_BGRA) {
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return ((src_pixel << 24) & 0xff000000)
+ | ((src_pixel >> 24) & 0x000000ff)
+ | ((src_pixel << 8) & 0x00ff0000)
+ | ((src_pixel >> 8) & 0x0000ff00);
+ } else {
+ return src_pixel;
+ }
+ } else { // GL_RGBA
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
+ return (src_pixel << 8) | ((src_pixel >> 24) & 0xff);
+ } else {
+ return ((src_pixel << 16) & 0xff0000)
+ | ((src_pixel >> 16) & 0xff)
+ | (src_pixel & 0xff00ff00);
+ }
+ }
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/texturehelper_p.h b/src/datavis3d/utils/texturehelper_p.h
new file mode 100644
index 00000000..4b420fa4
--- /dev/null
+++ b/src/datavis3d/utils/texturehelper_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef TEXTUREHELPER_P_H
+#define TEXTUREHELPER_P_H
+
+#include "qdatavis3dglobal.h"
+#include <QOpenGLFunctions>
+#include <QRgb>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class TextureHelper : protected QOpenGLFunctions
+{
+ public:
+ TextureHelper();
+ ~TextureHelper();
+
+ // Ownership of created texture is transferred to caller
+ GLuint create2DTexture(const QImage &image, bool useTrilinearFiltering = false,
+ bool convert = true);
+ GLuint createCubeMapTexture(const QImage &image, bool useTrilinearFiltering = false);
+ // Returns selection framebuffer and inserts generated texture id to texture parameters
+ GLuint createSelectionBuffer(const QSize &size, GLuint &texture, GLuint &depthTexture);
+ // Returns selection texture and inserts generated framebuffers to framebuffer parameters
+ GLuint createSelectionTexture(const QSize &size, GLuint &frameBuffer, GLuint &depthBuffer);
+ // Returns depth texture and inserts generated framebuffer to parameter
+ GLuint createDepthTexture(const QSize &size, GLuint &frameBuffer, GLuint textureSize = 1);
+ void deleteTexture(const GLuint *texture);
+
+ private:
+ QImage convertToGLFormat(const QImage &srcImage);
+ void convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage, GLenum texture_format);
+ QRgb qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format);
+
+ friend class Q3DBarsPrivate;
+ friend class Q3DMapsPrivate;
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/utils.cpp b/src/datavis3d/utils/utils.cpp
new file mode 100644
index 00000000..7b4cb6f6
--- /dev/null
+++ b/src/datavis3d/utils/utils.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "utils_p.h"
+
+#include <QVector3D>
+#include <QColor>
+#include <QPainter>
+#include <QPoint>
+#include <QImage>
+
+#include <qmath.h>
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+QVector3D Utils::vectorFromColor(const QColor &color)
+{
+ return QVector3D(color.redF(), color.greenF(), color.blueF());
+}
+
+void Utils::printText(QPainter *painter, const QString &text, const QSize &position,
+ bool absoluteCoords, qreal rotation, qreal scale)
+{
+ painter->save();
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+ painter->setPen(Qt::black); // TODO: Use black, as nothing works
+ QFont bgrFont = QFont(QStringLiteral("Arial"), 17);
+ QFont valueFont = QFont(QStringLiteral("Arial"), 11);
+ valueFont.setBold(true);
+ painter->setFont(bgrFont);
+ QFontMetrics valueFM(valueFont);
+ QFontMetrics bgrFM(bgrFont);
+ int valueStrLen = valueFM.width(text);
+ int bgrStrLen = 0;
+ int bgrHeight = valueFM.height() + 8;
+ QString bgrStr = QString();
+ do {
+ bgrStr.append(QStringLiteral("I"));
+ bgrStrLen = bgrFM.width(bgrStr);
+ } while (bgrStrLen <= (valueStrLen + 8));
+#if 0
+ // Hack solution, as drawRect doesn't work
+ painter->drawText(position.width() - (bgrStrLen / 2),
+ position.height() - bgrHeight,
+ bgrStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ bgrStr);
+ //painter->setPen(d_ptr->m_textColor);
+ painter->setPen(Qt::lightGray); // TODO: Use lightGray, as nothing works
+ painter->setFont(valueFont);
+ painter->drawText(position.width() - (valueStrLen / 2),
+ position.height() - bgrHeight,
+ valueStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+#else
+ //qDebug() << painter->window() << painter->viewport();
+ painter->scale(scale, scale);
+ if (absoluteCoords) {
+ // This assumes absolute screen coordinates
+ painter->translate(position.width() - (((float)bgrStrLen / 2.0f)
+ * cos(rotation * m_pi / 180.0f))
+ + (((float)bgrHeight / 2.0f) * sin(rotation * m_pi / 180.0f)),
+ position.height()
+ - ((((float)bgrHeight / 2.0f) * cos(rotation * m_pi / 180.0f))
+ + (((float)bgrStrLen / 2.0f) * sin(rotation * m_pi / 180.0f))));
+ } else {
+ // This calculates y as a distance from screen bottom
+ painter->translate(position.width() - (((float)bgrStrLen / 2.0f)
+ * cos(rotation * m_pi / 180.0f))
+ + (((float)bgrHeight / 2.0f) * sin(rotation * m_pi / 180.0f)),
+ painter->window().height() - position.height()
+ - ((((float)bgrHeight / 2.0f) * cos(rotation * m_pi / 180.0f))
+ + (((float)bgrStrLen / 2.0f) * sin(rotation * m_pi / 180.0f))));
+ }
+ //qDebug() << painter->window().height() - position.height()
+ // - ((((float)bgrHeight / 2.0f) * cos(rotation * m_pi / 180.0f))
+ // + (((float)bgrStrLen / 2.0f) * sin(rotation * m_pi / 180.0f)));
+ painter->rotate(rotation);
+ painter->drawText(0, 0,
+ bgrStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ bgrStr);
+ painter->setPen(Qt::lightGray); // TODO: Use lightGray, as nothing works
+ painter->setFont(valueFont);
+ painter->drawText(6, 0,
+ valueStrLen, bgrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ painter->resetTransform();
+#endif
+ painter->restore();
+}
+
+QImage Utils::printTextToImage(const QFont &font, const QString &text, const QColor &bgrColor,
+ const QColor &txtColor, LabelTransparency transparency)
+{
+ // Calculate text dimensions
+ QFont valueFont = font;
+ valueFont.setPointSize(30);
+ QFontMetrics valueFM(valueFont);
+ int valueStrWidth = valueFM.width(text);
+ int valueStrHeight = valueFM.height();
+ QSize labelSize;
+ if (TransparencyNoBackground == transparency)
+ labelSize = QSize(valueStrWidth, valueStrHeight);
+ else
+ labelSize = QSize(valueStrWidth + 30, valueStrHeight + 30);
+
+ // Create image
+ QImage image = QImage(labelSize, QImage::Format_ARGB32);
+ image.fill(Qt::transparent);
+
+ // Init painter
+ QPainter painter(&image);
+ // Paint text
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ switch (transparency) {
+ case TransparencyNoBackground: {
+ painter.setFont(valueFont);
+ painter.setPen(txtColor);
+ painter.drawText(0, 0,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ break;
+ }
+ case TransparencyFromTheme: {
+ painter.setBrush(QBrush(bgrColor));
+ painter.setPen(bgrColor);
+ painter.drawRoundedRect(0, 0, labelSize.width(), labelSize.height(), 10.0, 10.0f);
+ painter.setFont(valueFont);
+ painter.setPen(txtColor);
+ painter.drawText(15, 15,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ break;
+ }
+ case TransparencyNone: {
+ painter.setBrush(QBrush(bgrColor));
+ painter.setPen(bgrColor);
+ painter.drawRect(0, 0, labelSize.width(), labelSize.height());
+ painter.setFont(valueFont);
+ painter.setPen(txtColor);
+ painter.drawText(15, 15,
+ valueStrWidth, valueStrHeight,
+ Qt::AlignCenter | Qt::AlignVCenter,
+ text);
+ break;
+ }
+ }
+ return image;
+}
+
+QVector3D Utils::getSelection(QPoint mousepos, int height)
+{
+ QVector3D selectedColor;
+
+ // This is the only one that works with ANGLE (ES 2.0)
+ // Item count will be limited to 256*256*256
+ GLubyte pixel[4];
+ glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1,
+ GL_RGBA, GL_UNSIGNED_BYTE, (void *)pixel);
+
+ // These work with desktop OpenGL
+ // They offer a lot higher possible object count and a possibility to use object id's
+ //GLuint pixel2[3];
+ //glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1,
+ // GL_RGB, GL_UNSIGNED_INT, (void *)pixel2);
+
+ //GLfloat pixel3[3];
+ //glReadPixels(mousepos.x(), height - mousepos.y(), 1, 1,
+ // GL_RGB, GL_FLOAT, (void *)pixel3);
+
+ //qDebug() << "rgba" << pixel[0] << pixel[1] << pixel[2];// << pixel[3];
+ //qDebug() << "rgba2" << pixel2[0] << pixel2[1] << pixel2[2];
+ //qDebug() << "rgba3" << pixel3[0] << pixel3[1] << pixel3[2];
+ selectedColor = QVector3D(pixel[0], pixel[1], pixel[2]);
+ //qDebug() << selectedColor;
+
+ return selectedColor;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/utils.pri b/src/datavis3d/utils/utils.pri
new file mode 100644
index 00000000..566af55f
--- /dev/null
+++ b/src/datavis3d/utils/utils.pri
@@ -0,0 +1,15 @@
+HEADERS += $$PWD/meshloader_p.h \
+ $$PWD/vertexindexer_p.h \
+ $$PWD/camerahelper_p.h \
+ $$PWD/shaderhelper_p.h \
+ $$PWD/objecthelper_p.h \
+ $$PWD/texturehelper_p.h \
+ $$PWD/utils_p.h
+
+SOURCES += $$PWD/meshloader.cpp \
+ $$PWD/vertexindexer.cpp \
+ $$PWD/camerahelper.cpp \
+ $$PWD/shaderhelper.cpp \
+ $$PWD/objecthelper.cpp \
+ $$PWD/texturehelper.cpp \
+ $$PWD/utils.cpp
diff --git a/src/datavis3d/utils/utils_p.h b/src/datavis3d/utils/utils_p.h
new file mode 100644
index 00000000..1668ac40
--- /dev/null
+++ b/src/datavis3d/utils/utils_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef UTILS_P_H
+#define UTILS_P_H
+
+#include "qdatavis3dglobal.h"
+#include "qdatavis3namespace.h"
+#include "q3dbars.h"
+
+class QVector3D;
+class QColor;
+class QPainter;
+class QString;
+class QPoint;
+class QImage;
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class Utils
+{
+ public:
+ static QVector3D vectorFromColor(const QColor &color);
+ static void printText(QPainter *painter, const QString &text, const QSize &position,
+ bool absoluteCoords = true, qreal rotation = 0, qreal scale = 1.0f);
+ static QImage printTextToImage(const QFont &font,
+ const QString &text,
+ const QColor &bgrColor,
+ const QColor &txtColor,
+ LabelTransparency transparency);
+ static QVector3D getSelection(QPoint mousepos, int height);
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif
diff --git a/src/datavis3d/utils/vertexindexer.cpp b/src/datavis3d/utils/vertexindexer.cpp
new file mode 100644
index 00000000..7e5a863f
--- /dev/null
+++ b/src/datavis3d/utils/vertexindexer.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "vertexindexer_p.h"
+
+#include <string.h> // for memcmp
+#include <qmath.h>
+
+#include <QDebug>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+int unique_vertices = 0;
+
+// Returns true if v1 can be considered equal to v2
+bool VertexIndexer::is_near(float v1, float v2)
+{
+ return qFabs(v1 - v2) < 0.01f;
+}
+
+// Searches through all already-exported vertices
+// for a similar one.
+// Similar = same position + same UVs + same normal
+bool VertexIndexer::getSimilarVertexIndex(const QVector3D &in_vertex,
+ const QVector2D &in_uv,
+ const QVector3D &in_normal,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ unsigned short &result)
+{
+ // Lame linear search
+ for (int i = 0; i < out_vertices.size(); i++) {
+ if (is_near(in_vertex.x() , out_vertices[i].x())
+ && is_near(in_vertex.y() , out_vertices[i].y())
+ && is_near(in_vertex.z() , out_vertices[i].z())
+ && is_near(in_uv.x() , out_uvs [i].x())
+ && is_near(in_uv.y() , out_uvs [i].y())
+ && is_near(in_normal.x() , out_normals [i].x())
+ && is_near(in_normal.y() , out_normals [i].y())
+ && is_near(in_normal.z() , out_normals [i].z())) {
+ result = i;
+ return true;
+ }
+ }
+ // No other vertex could be used instead.
+ // Looks like we'll have to add it to the VBO.
+ return false;
+}
+
+bool VertexIndexer::getSimilarVertexIndex_fast(const PackedVertex &packed,
+ QMap<PackedVertex, unsigned short> &VertexToOutIndex,
+ unsigned short &result)
+{
+ QMap<PackedVertex, unsigned short>::iterator it = VertexToOutIndex.find(packed);
+ if (it == VertexToOutIndex.end()) {
+ return false;
+ } else {
+ result = it.value();
+ return true;
+ }
+}
+
+void VertexIndexer::indexVBO(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals)
+{
+ unique_vertices = 0;
+ QMap<PackedVertex, unsigned short> VertexToOutIndex;
+
+ // For each input vertex
+ for (int i = 0; i < in_vertices.size(); i++) {
+ PackedVertex packed = {in_vertices[i], in_uvs[i], in_normals[i]};
+
+ // Try to find a similar vertex in out_XXXX
+ unsigned short index;
+ bool found = getSimilarVertexIndex_fast(packed, VertexToOutIndex, index);
+
+ if (found) {
+ out_indices.append(index);
+ } else {
+ unique_vertices++;
+ out_vertices.append(in_vertices[i]);
+ out_uvs.append(in_uvs[i]);
+ out_normals.append(in_normals[i]);
+ unsigned short newindex = (unsigned short)out_vertices.size() - 1;
+ out_indices.append(newindex);
+ VertexToOutIndex[packed] = newindex;
+ }
+ }
+ //qDebug() << "unique vertices" << unique_vertices;
+}
+
+void VertexIndexer::indexVBO_TBN(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ const QVector<QVector3D> &in_tangents,
+ const QVector<QVector3D> &in_bitangents,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ QVector<QVector3D> &out_tangents,
+ QVector<QVector3D> &out_bitangents)
+{
+ unique_vertices = 0;
+ // For each input vertex
+ for (int i = 0; i < in_vertices.size(); i++) {
+
+ // Try to find a similar vertex in out_XXXX
+ unsigned short index;
+ bool found = getSimilarVertexIndex(in_vertices[i], in_uvs[i], in_normals[i],
+ out_vertices, out_uvs, out_normals, index);
+
+ if (found) {
+ out_indices.append(index);
+
+ // Average the tangents and the bitangents
+ out_tangents[index] += in_tangents[i];
+ out_bitangents[index] += in_bitangents[i];
+ } else {
+ unique_vertices++;
+ out_vertices.append(in_vertices[i]);
+ out_uvs.append(in_uvs[i]);
+ out_normals.append(in_normals[i]);
+ out_tangents.append(in_tangents[i]);
+ out_bitangents.append(in_bitangents[i]);
+ out_indices.append((unsigned short)out_vertices.size() - 1);
+ }
+ }
+ //qDebug() << "unique vertices" << unique_vertices;
+}
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
diff --git a/src/datavis3d/utils/vertexindexer_p.h b/src/datavis3d/utils/vertexindexer_p.h
new file mode 100644
index 00000000..3ee908af
--- /dev/null
+++ b/src/datavis3d/utils/vertexindexer_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtDataVis3D module.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef VERTEXINDEXER_P_H
+#define VERTEXINDEXER_P_H
+
+#include "qdatavis3dglobal.h"
+
+#include <QVector>
+#include <QVector2D>
+#include <QVector3D>
+
+QTCOMMERCIALDATAVIS3D_BEGIN_NAMESPACE
+
+class VertexIndexer
+{
+ public:
+ struct PackedVertex {
+ QVector3D position;
+ QVector2D uv;
+ QVector3D normal;
+ bool operator<(const PackedVertex that) const {
+ return memcmp((void*)this, (void*)&that, sizeof(PackedVertex)) > 0;
+ }
+ };
+
+ static void indexVBO(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals);
+
+ static void indexVBO_TBN(const QVector<QVector3D> &in_vertices,
+ const QVector<QVector2D> &in_uvs,
+ const QVector<QVector3D> &in_normals,
+ const QVector<QVector3D> &in_tangents,
+ const QVector<QVector3D> &in_bitangents,
+ QVector<unsigned short> &out_indices,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ QVector<QVector3D> &out_tangents,
+ QVector<QVector3D> &out_bitangents);
+
+ private:
+ static bool is_near(float v1, float v2);
+ static bool getSimilarVertexIndex(const QVector3D &in_vertex,
+ const QVector2D &in_uv,
+ const QVector3D &in_normal,
+ QVector<QVector3D> &out_vertices,
+ QVector<QVector2D> &out_uvs,
+ QVector<QVector3D> &out_normals,
+ unsigned short &result);
+ static bool getSimilarVertexIndex_fast(const PackedVertex &packed,
+ QMap<PackedVertex, unsigned short> &VertexToOutIndex,
+ unsigned short &result);
+};
+
+QTCOMMERCIALDATAVIS3D_END_NAMESPACE
+
+#endif