From 5e84b7f6a2ffeb783f269052a899f0f05643fc9f Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 16 Feb 2017 12:52:39 -0700 Subject: [PATCH 001/192] new touch module with TUIO library to make OpenSpace tuio-aware --- apps/OpenSpace/main.cpp | 4 + data/scene/atmosphereearth.scene | 3 +- data/scene/lodglobes/earth/earth.mod | 4 + data/scene/newhorizons.scene | 2 +- data/web/log/script.js | 2 +- data/web/log/style.css | 9 - modules/touch/CMakeLists.txt | 43 + modules/touch/ext/.vs/libTUIO2/v14/.suo | Bin 0 -> 5632 bytes modules/touch/ext/libTUIO2/CMakeLists.txt | 63 ++ modules/touch/ext/libTUIO2/TUIO2/Doxyfile | 15 + .../touch/ext/libTUIO2/TUIO2/FlashSender.cpp | 650 ++++++++++++++ .../touch/ext/libTUIO2/TUIO2/FlashSender.h | 215 +++++ modules/touch/ext/libTUIO2/TUIO2/LibExport.h | 36 + .../touch/ext/libTUIO2/TUIO2/OscReceiver.cpp | 60 ++ .../touch/ext/libTUIO2/TUIO2/OscReceiver.h | 97 +++ modules/touch/ext/libTUIO2/TUIO2/OscSender.h | 90 ++ .../touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp | 264 ++++++ .../touch/ext/libTUIO2/TUIO2/TcpReceiver.h | 102 +++ .../touch/ext/libTUIO2/TUIO2/TcpSender.cpp | 303 +++++++ modules/touch/ext/libTUIO2/TUIO2/TcpSender.h | 126 +++ .../touch/ext/libTUIO2/TUIO2/TuioBounds.cpp | 94 +++ modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h | 206 +++++ .../touch/ext/libTUIO2/TUIO2/TuioClient.cpp | 520 ++++++++++++ modules/touch/ext/libTUIO2/TUIO2/TuioClient.h | 241 ++++++ .../ext/libTUIO2/TUIO2/TuioComponent.cpp | 245 ++++++ .../touch/ext/libTUIO2/TUIO2/TuioComponent.h | 287 +++++++ .../ext/libTUIO2/TUIO2/TuioDispatcher.cpp | 165 ++++ .../touch/ext/libTUIO2/TUIO2/TuioDispatcher.h | 169 ++++ .../touch/ext/libTUIO2/TUIO2/TuioListener.h | 80 ++ .../touch/ext/libTUIO2/TUIO2/TuioManager.cpp | 575 +++++++++++++ .../touch/ext/libTUIO2/TUIO2/TuioManager.h | 601 +++++++++++++ .../touch/ext/libTUIO2/TUIO2/TuioObject.cpp | 311 +++++++ modules/touch/ext/libTUIO2/TUIO2/TuioObject.h | 341 ++++++++ .../touch/ext/libTUIO2/TUIO2/TuioPoint.cpp | 124 +++ modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h | 213 +++++ .../touch/ext/libTUIO2/TUIO2/TuioPointer.cpp | 132 +++ .../touch/ext/libTUIO2/TUIO2/TuioPointer.h | 263 ++++++ .../touch/ext/libTUIO2/TUIO2/TuioServer.cpp | 329 ++++++++ modules/touch/ext/libTUIO2/TUIO2/TuioServer.h | 210 +++++ modules/touch/ext/libTUIO2/TUIO2/TuioSource.h | 244 ++++++ .../touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp | 91 ++ modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h | 160 ++++ modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp | 160 ++++ modules/touch/ext/libTUIO2/TUIO2/TuioTime.h | 222 +++++ .../touch/ext/libTUIO2/TUIO2/TuioToken.cpp | 69 ++ modules/touch/ext/libTUIO2/TUIO2/TuioToken.h | 151 ++++ .../touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp | 92 ++ .../touch/ext/libTUIO2/TUIO2/UdpReceiver.h | 77 ++ .../touch/ext/libTUIO2/TUIO2/UdpSender.cpp | 89 ++ modules/touch/ext/libTUIO2/TUIO2/UdpSender.h | 93 ++ .../ext/libTUIO2/TUIO2/WebSockSender.cpp | 286 +++++++ .../touch/ext/libTUIO2/TUIO2/WebSockSender.h | 121 +++ modules/touch/ext/libTUIO2/oscpack/CHANGES | 159 ++++ modules/touch/ext/libTUIO2/oscpack/LICENSE | 34 + modules/touch/ext/libTUIO2/oscpack/README | 150 ++++ modules/touch/ext/libTUIO2/oscpack/TODO | 52 ++ .../libTUIO2/oscpack/ip/IpEndpointName.cpp | 88 ++ .../ext/libTUIO2/oscpack/ip/IpEndpointName.h | 83 ++ .../ext/libTUIO2/oscpack/ip/NetworkingUtils.h | 56 ++ .../ext/libTUIO2/oscpack/ip/PacketListener.h | 50 ++ .../ext/libTUIO2/oscpack/ip/TimerListener.h | 47 ++ .../touch/ext/libTUIO2/oscpack/ip/UdpSocket.h | 176 ++++ .../oscpack/ip/posix/NetworkingUtils.cpp | 64 ++ .../libTUIO2/oscpack/ip/posix/UdpSocket.cpp | 602 +++++++++++++ .../oscpack/ip/win32/NetworkingUtils.cpp | 95 +++ .../libTUIO2/oscpack/ip/win32/UdpSocket.cpp | 571 +++++++++++++ .../osc/MessageMappingOscPacketListener.h | 80 ++ .../ext/libTUIO2/oscpack/osc/OscException.h | 62 ++ .../libTUIO2/oscpack/osc/OscHostEndianness.h | 127 +++ .../oscpack/osc/OscOutboundPacketStream.cpp | 683 +++++++++++++++ .../oscpack/osc/OscOutboundPacketStream.h | 154 ++++ .../libTUIO2/oscpack/osc/OscPacketListener.h | 79 ++ .../oscpack/osc/OscPrintReceivedElements.cpp | 261 ++++++ .../oscpack/osc/OscPrintReceivedElements.h | 54 ++ .../oscpack/osc/OscReceivedElements.cpp | 796 ++++++++++++++++++ .../oscpack/osc/OscReceivedElements.h | 548 ++++++++++++ .../ext/libTUIO2/oscpack/osc/OscTypes.cpp | 52 ++ .../touch/ext/libTUIO2/oscpack/osc/OscTypes.h | 240 ++++++ modules/touch/include.cmake | 1 + modules/touch/include/TuioEar.h | 62 ++ modules/touch/src/TuioEar.cpp | 89 ++ modules/touch/touchmodule.cpp | 33 + modules/touch/touchmodule.h | 39 + openspace.cfg | 2 +- 84 files changed, 14625 insertions(+), 13 deletions(-) create mode 100644 modules/touch/CMakeLists.txt create mode 100644 modules/touch/ext/.vs/libTUIO2/v14/.suo create mode 100644 modules/touch/ext/libTUIO2/CMakeLists.txt create mode 100644 modules/touch/ext/libTUIO2/TUIO2/Doxyfile create mode 100644 modules/touch/ext/libTUIO2/TUIO2/FlashSender.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/FlashSender.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/LibExport.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/OscReceiver.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/OscReceiver.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/OscSender.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TcpSender.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TcpSender.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioClient.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioListener.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioManager.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioObject.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioPoint.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioServer.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioSource.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioTime.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioToken.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/UdpSender.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/UdpSender.h create mode 100644 modules/touch/ext/libTUIO2/TUIO2/WebSockSender.cpp create mode 100644 modules/touch/ext/libTUIO2/TUIO2/WebSockSender.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/CHANGES create mode 100644 modules/touch/ext/libTUIO2/oscpack/LICENSE create mode 100644 modules/touch/ext/libTUIO2/oscpack/README create mode 100644 modules/touch/ext/libTUIO2/oscpack/TODO create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/NetworkingUtils.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/PacketListener.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/TimerListener.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/UdpSocket.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/posix/NetworkingUtils.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/posix/UdpSocket.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/win32/NetworkingUtils.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/ip/win32/UdpSocket.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/MessageMappingOscPacketListener.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscException.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscHostEndianness.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscPacketListener.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.h create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.cpp create mode 100644 modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.h create mode 100644 modules/touch/include.cmake create mode 100644 modules/touch/include/TuioEar.h create mode 100644 modules/touch/src/TuioEar.cpp create mode 100644 modules/touch/touchmodule.cpp create mode 100644 modules/touch/touchmodule.h diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 90fe52a028..a0c5f2b6d8 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -33,6 +33,8 @@ #include #include +#include + sgct::Engine* _sgctEngine; void mainInitFunc(); @@ -84,6 +86,8 @@ namespace { int main(int argc, char** argv) { auto glVersion = supportedOpenGLVersion(); + TuioEar *ear = new TuioEar(); + // create the OpenSpace engine and get arguments for the sgct engine std::vector sgctArguments; const bool success = openspace::OpenSpaceEngine::create( diff --git a/data/scene/atmosphereearth.scene b/data/scene/atmosphereearth.scene index 914c040ca7..598240dc5f 100644 --- a/data/scene/atmosphereearth.scene +++ b/data/scene/atmosphereearth.scene @@ -41,7 +41,8 @@ return { CommonFolder = "common", Camera = { Focus = "Earth", - Position = {1, 0, 0, 2}, + Position = {1, 0, 0}, + Rotation = {0.250635, -0.028751, 0.879269, 0.404030}, }, Modules = { "sun", diff --git a/data/scene/lodglobes/earth/earth.mod b/data/scene/lodglobes/earth/earth.mod index 1df4498c85..9bd4c8277b 100644 --- a/data/scene/lodglobes/earth/earth.mod +++ b/data/scene/lodglobes/earth/earth.mod @@ -71,6 +71,10 @@ return { }, Enabled = true, }, + { + FilePath = "map_service_configs/ESRI/ESRI_Imagery_World_2D.wms", + Name = "ESRI", + }, { Type = "Temporal", Name = "Temporal VIIRS SNPP", diff --git a/data/scene/newhorizons.scene b/data/scene/newhorizons.scene index ca5e4106c9..36084aa2a4 100644 --- a/data/scene/newhorizons.scene +++ b/data/scene/newhorizons.scene @@ -1,4 +1,4 @@ -UseAccurateNewHorizonsKernels = true +UseAccurateNewHorizonsKernels = false -- TextureResolution = "low" TextureResolution = "med" -- TextureResolution = "high" diff --git a/data/web/log/script.js b/data/web/log/script.js index ac198a1189..fea743117f 100644 --- a/data/web/log/script.js +++ b/data/web/log/script.js @@ -1,4 +1,4 @@ -var levels = ['trace', 'debug', 'info', 'warning', 'error', 'fatal']; +var levels = ['debug', 'info', 'warning', 'error', 'fatal']; var filterLevel = 0; function insertAfter(newNode, referenceNode) { diff --git a/data/web/log/style.css b/data/web/log/style.css index 80a17198ed..3aa140b30e 100644 --- a/data/web/log/style.css +++ b/data/web/log/style.css @@ -27,15 +27,6 @@ label { margin-right: 0.5em; } -.log-level-trace { - color: #eeeeee; - background-color: #aaaaaa; - border-bottom: 1px solid #eaeaea; -} -.log-level-trace td:first-child { - border-left: 10px solid #eaeaea; -} - .log-level-debug { background-color: #bbdda9; border-bottom: 1px solid #7bc142; diff --git a/modules/touch/CMakeLists.txt b/modules/touch/CMakeLists.txt new file mode 100644 index 0000000000..c2e655c546 --- /dev/null +++ b/modules/touch/CMakeLists.txt @@ -0,0 +1,43 @@ +######################################################################################### +# # +# OpenSpace # +# # +# Copyright (c) 2014-2017 # +# # +# Permission is hereby granted, free of charge, to any person obtaining a copy of this # +# software and associated documentation files (the "Software"), to deal in the Software # +# without restriction, including without limitation the rights to use, copy, modify, # +# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # +# permit persons to whom the Software is furnished to do so, subject to the following # +# conditions: # +# # +# The above copyright notice and this permission notice shall be included in all copies # +# or substantial portions of the Software. # +# # +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE # +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +######################################################################################### + +include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/include/TuioEar.h +) +source_group("Header Files" FILES ${HEADER_FILES}) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/TuioEar.cpp +) +source_group("Source Files" FILES ${SOURCE_FILES}) + +create_new_module( + "Touch" + touch_module + ${HEADER_FILES} ${SOURCE_FILES} +) + +include_external_library(${touch_module} libTUIO2 ${CMAKE_CURRENT_SOURCE_DIR}/ext/libTUIO2) \ No newline at end of file diff --git a/modules/touch/ext/.vs/libTUIO2/v14/.suo b/modules/touch/ext/.vs/libTUIO2/v14/.suo new file mode 100644 index 0000000000000000000000000000000000000000..cc39013d5358149db3c8b246adf0aaf2dfa512c5 GIT binary patch literal 5632 zcmeHL&ubGw6#h1~wMCE=O2FcwU@smN?9oFH#vTenO4HtQuuZE;P0}CPgcf?}LGa>5 zp=Vn?7wy%9M^O>rMn z;Dbr@;kZ160Z+d}JY?xGaE`e8j?3k;y8Cz&4WNrGFpE`QF2*p09NP_S$(2n*1pOyI zm;W0#a zhiq}9!dCY=j*w&XQg*1z=ot|I+bXTx{p~ei6<5FR0D9X3|1$qyJzh8YKg8JEseVY> zkpGU?L!L0Ni%NeR^WRY}+d0%#>Ko{k{I~Pgo~V7mpZB5%J?pdlLE9S^kbjkm`gSWO zMeEF`Z?ydGkB8n^b+8I+fz!?(6O4gI!1Kq+-lumq; z6sbIG9#Ju@nXx$A1@bPlFH5N4}thkmp6n-)OAm*-re=_o6_}Rs4wWFO+SxdA! z({5jXtLyF+xgh_Q0j+!UdB^O3^V}`hFw31!`)3+OKJ_Ong@aP&>6=Smziofqe|X{3 K-b=04=KUY%-t)5n literal 0 HcmV?d00001 diff --git a/modules/touch/ext/libTUIO2/CMakeLists.txt b/modules/touch/ext/libTUIO2/CMakeLists.txt new file mode 100644 index 0000000000..4fe0af8650 --- /dev/null +++ b/modules/touch/ext/libTUIO2/CMakeLists.txt @@ -0,0 +1,63 @@ +######################################################################################### +# # +# OpenSpace # +# # +# Copyright (c) 2014-2016 # +# # +# Permission is hereby granted, free of charge, to any person obtaining a copy of this # +# software and associated documentation files (the "Software"), to deal in the Software # +# without restriction, including without limitation the rights to use, copy, modify, # +# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # +# permit persons to whom the Software is furnished to do so, subject to the following # +# conditions: # +# # +# The above copyright notice and this permission notice shall be included in all copies # +# or substantial portions of the Software. # +# # +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE # +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +######################################################################################### + +project(libTUIO2) +message(STATUS "Generating libTUIO2 project") + +add_library(libTUIO2 + ${PROJECT_SOURCE_DIR}/TUIO2/WebSockSender.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/UdpSender.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/UdpReceiver.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioToken.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioTime.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioSymbol.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioServer.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioPointer.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioPoint.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioObject.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioManager.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioDispatcher.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioComponent.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioClient.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TuioBounds.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TcpSender.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/TcpReceiver.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/OscReceiver.cpp + ${PROJECT_SOURCE_DIR}/TUIO2/FlashSender.cpp + + ${PROJECT_SOURCE_DIR}/oscpack/ip/IpEndpointName.cpp + + #if (WIN32) + ${PROJECT_SOURCE_DIR}/oscpack/ip/win32/NetworkingUtils.cpp + ${PROJECT_SOURCE_DIR}/oscpack/ip/win32/UdpSocket.cpp + #else (WIN32) + #${PROJECT_SOURCE_DIR}/oscpack/ip/posix/NetworkingUtils.cpp + #${PROJECT_SOURCE_DIR}/oscpack/ip/posix/UdpSocket.cpp + #endif () + ${PROJECT_SOURCE_DIR}/oscpack/osc/OscTypes.cpp + ${PROJECT_SOURCE_DIR}/oscpack/osc/OscReceivedElements.cpp + ${PROJECT_SOURCE_DIR}/oscpack/osc/OscPrintReceivedElements.cpp + ${PROJECT_SOURCE_DIR}/oscpack/osc/OscOutboundPacketStream.cpp +) +target_include_directories(libTUIO2 PUBLIC ${PROJECT_SOURCE_DIR}) \ No newline at end of file diff --git a/modules/touch/ext/libTUIO2/TUIO2/Doxyfile b/modules/touch/ext/libTUIO2/TUIO2/Doxyfile new file mode 100644 index 0000000000..123a23ec35 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/Doxyfile @@ -0,0 +1,15 @@ +# Doxyfile 1.5.6 +# Project related configuration options +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "TUIO2 C++ Developer API" +# Build related configuration options +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +# configuration options related to the HTML output +GENERATE_HTML = YES +HTML_OUTPUT = ../doc +HTML_FILE_EXTENSION = .html +GENERATE_TREEVIEW = YES +GENERATE_LATEX = NO diff --git a/modules/touch/ext/libTUIO2/TUIO2/FlashSender.cpp b/modules/touch/ext/libTUIO2/TUIO2/FlashSender.cpp new file mode 100644 index 0000000000..d3e9f2237b --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/FlashSender.cpp @@ -0,0 +1,650 @@ +#include "FlashSender.h" + +// Copyright (C) 2009 Georg Kaindl +// This file is part of Touché. +// +// Touché is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// Touché is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with Touché. If not, see . + + +#include +#include +#include +#include + +#if !defined(WIN32) +#include +#include +#include +#include + +#if defined(__APPLE__) +#include +#include +#else +#include +#endif + +#endif + +#define FLASHLC_SHM_SIZE (64528) // This is what Flash always uses as size +#define FLASHLC_SHM_LISTENERS_OFFSET (40976) // Another "magic number" +#define MAX_LISTENER_NAME_LEN (64) +#define MAX_LISTENER_METHOD_NAME (64) + +#define PROTOCOL_NAME ("localhost") + +#define WIN32_SEMAPHORE_NAME TEXT("MacromediaMutexOmega") +#define WIN32_SHMEM_NAME TEXT("MacromediaFMOmega") +#define POSIX_SEMAPHORE_NAME ("MacromediaSemaphoreDig") +#define POSIX_SEMAPHORE_INITIAL_VALUE (10) + +#define AMF_TYPE_STRING (0x02) +#define AMF_TYPE_AMF3OBJ (0x11) +#define AMF3_TYPE_BYTEARRAY (0x0C) + +#define AMF_ENVELOPE_LEN (16) +#define AMF_ENVELOPE_TIMESTAMP_POS (8) +#define AMF_ENVELOPE_SIZE_POS (12) + +void _TFLCSLockSemaphore(TFLCSLocalConnection_t* connection); +void _TFLCSUnlockSemaphore(TFLCSLocalConnection_t* connection); + +// returns non-zero if the given connection is in a usable state, zero otherwise +int _TFLCSConnectionStructureIsValidForUse(TFLCSLocalConnection_t* connection); + +// On WIN32, we cannot create the shared memory and semaphore ourselves, because +// we don't know the exact parameters. Therefore, if Flash is not running when we +// try to connect, we'll try again whenever we should send data, until we finally +// manage to connect. +int _TFLCSDelayedConnect(TFLCSLocalConnection_t* connection); + +#define ENSURE_CONNECTION_UP(c, rv) do { if (!(c)->open && !_TFLCSDelayedConnect((c))) return (rv); } while (0) + +u_int32_t _TFLCSKnownDarwinKeys[] = { 0x53414e44, 0 }; + +TFLCSError_t TFLCSErrno = TFLCSErrorSuccess; + +TFLCSLocalConnection_t* TFLCSConnect(const char* listenerName, + const char* listenerMethod, + void* shmemKey, + void* semaphoreKey) +{ + TFLCSLocalConnection_t* connection = NULL; + + if (NULL == listenerName || NULL == listenerMethod || + strlen(listenerName) > TFLCS_LISTENER_NAME_MAX_LEN || + strlen(listenerMethod) > TFLCS_LISTENER_METHOD_MAX_LEN) { + TFLCSErrno = TFLCSErrorInvalidArgument; + return NULL; + } + + connection = (TFLCSLocalConnection_t*)malloc(sizeof(TFLCSLocalConnection_t)); + if (NULL == connection) { + TFLCSErrno = TFLCSErrorOutOfMemory; + goto errorReturn; + } + + connection->open = 0; + +#if defined(WIN32) + // initialize the structure + connection->semaphore = NULL; + connection->mapFile = NULL; + connection->mapAddress = NULL; + connection->data = NULL; + + _TFLCSDelayedConnect(connection); +#else + // initialize the structure + connection->semaphore = (sem_t*)SEM_FAILED; + connection->shmid = -1; + connection->data = (char*)-1; + + // we don't need a delayed connect on MacOS X, so let's just connect now! + key_t key; + char* semName; + + if (NULL != shmemKey) + key = *(key_t*)shmemKey; + else { + key_t* guessedKey = (key_t*)TFLCSGuessShmemKey(); + if (NULL != guessedKey) + key = *(key_t*)guessedKey; + else { + TFLCSErrno = TFLCSErrorShmemKeyNotFound; + goto errorReturn; + } + } + + if (NULL != semaphoreKey) + semName = (char*)semaphoreKey; + else + semName = (char*)POSIX_SEMAPHORE_NAME; + + connection->semaphore = sem_open(semName, + O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, + POSIX_SEMAPHORE_INITIAL_VALUE); + if ((sem_t*)SEM_FAILED == connection->semaphore) { + TFLCSErrno = TFLCSErrorSemaphoreCreationFailed; + goto errorReturn; + } + + if (-1 == (connection->shmid = shmget(key, FLASHLC_SHM_SIZE, 0666 | IPC_CREAT))) { + TFLCSErrno = TFLCSErrorShmemIDNotFound; + goto errorReturn; + } + + connection->data = (char*)shmat(connection->shmid, NULL, 0); + if ((char*)-1 == connection->data) { + TFLCSErrno = TFLCSErrorShmemOpeningFailed; + goto errorReturn; + } + + connection->open = 1; + + // initialize the memory region the way Flash likes it :-) + connection->data[0] = 1; + connection->data[4] = 1; +#endif + + strncpy(connection->listenerName, listenerName, TFLCS_LISTENER_NAME_MAX_LEN); + strncpy(connection->listenerMethod, listenerMethod, TFLCS_LISTENER_METHOD_MAX_LEN); + + return connection; + +errorReturn: + TFLCSDisconnect(connection); + + return NULL; +} + +void TFLCSDisconnect(TFLCSLocalConnection_t* connection) +{ + if (NULL != connection) { +#if defined(WIN32) + if (NULL != connection->semaphore) + CloseHandle(connection->semaphore); + + if (NULL != connection->mapAddress) + UnmapViewOfFile(connection->mapAddress); + + if (NULL != connection->mapFile) + CloseHandle(connection->mapFile); +#else + if ((sem_t*)SEM_FAILED != connection->semaphore) + sem_close(connection->semaphore); + + if ((char*)-1 != connection->data) + (void)shmdt(connection->data); +#endif + free(connection); + } +} + +void TFLCSChangeListenerName(TFLCSLocalConnection_t* connection, const char* newListenerName) +{ + if (NULL != connection && NULL != newListenerName) + strncpy(connection->listenerName, newListenerName, TFLCS_LISTENER_NAME_MAX_LEN); +} + +void TFLCSChangeMethodName(TFLCSLocalConnection_t* connection, const char* newMethodName) +{ + if (NULL != connection && NULL != newMethodName) + strncpy(connection->listenerMethod, newMethodName, TFLCS_LISTENER_METHOD_MAX_LEN); +} + +int TFLCSConnectionHasConnectedClient(TFLCSLocalConnection_t* connection) +{ + ENSURE_CONNECTION_UP(connection, 0); + + int retval = 0; + + if (_TFLCSConnectionStructureIsValidForUse(connection)) { + _TFLCSLockSemaphore(connection); + + int c, l = strlen(connection->listenerName); + char* p = &connection->data[FLASHLC_SHM_LISTENERS_OFFSET]; + + while (!retval && (char)0 != *p) { + c = strlen(p) + 1; + if (0 == strncmp(p, connection->listenerName, l)) + retval = 1; + + p += c; + } + + _TFLCSUnlockSemaphore(connection); + } + + return retval; +} + +int TFLCSGetConnectedConnectionNames(TFLCSLocalConnection_t* connection, char* dest, int destLen) +{ + ENSURE_CONNECTION_UP(connection, 0); + + int retval = 0; + + if (NULL != dest && 0 < destLen && _TFLCSConnectionStructureIsValidForUse(connection)) { + _TFLCSLockSemaphore(connection); + + int c, i=0; + char* p = &connection->data[FLASHLC_SHM_LISTENERS_OFFSET]; + + while ((char)0 != *p && destLen > 0) { + c = strlen(p) + 1; + if (0 == (i % 3)) { + strncpy(dest, p, destLen < c ? destLen : c); + destLen -= c; + dest += c; + } + + p += c; + i++; + } + + retval = i/3; + + _TFLCSUnlockSemaphore(connection); + } + + return retval; +} + +void* TFLCSGuessShmemKey() +{ +#if defined(WIN32) + return (void*)WIN32_SHMEM_NAME; +#else + static int found = 0; + static key_t key; + + // first, try our known keys + int i = 0; + while(!found && _TFLCSKnownDarwinKeys[i]) { + if (-1 != shmget(_TFLCSKnownDarwinKeys[i], FLASHLC_SHM_SIZE, 0)) { + found = 1; + key = _TFLCSKnownDarwinKeys[i]; + } + + i++; + } + + /* // magic numbers for MacOS X 10.5, probably later and earlier versions too, dunno... + int minid = 0xffff; + int maxid = 0x500000; + struct shmid_ds shm_info; + for (i=minid; !found && i<=maxid; i++) { + if (shmctl(i, IPC_STAT, &shm_info) < 0) + continue; + + if (FLASHLC_SHM_SIZE == shm_info.shm_segsz) { + found = 1; + key = shm_info.shm_perm._key; + } + } */ + + // if we didn't find anything, set the key to a reasonable guess + // this is necessary because the shared segment might not exist yet. + if (!found) { + key = _TFLCSKnownDarwinKeys[0]; + found = 1; + } + + return &key; +#endif +} + +u_int32_t TFLCSGetTickCount() +{ +#if defined(WIN32) + return (u_int32_t)GetTickCount(); +#elif defined(__APPLE__) + static mach_timebase_info_data_t timeBase; + + u_int64_t nanos = mach_absolute_time(); + + if (0 == timeBase.denom) { + (void)mach_timebase_info(&timeBase); + } + return (u_int32_t)((nanos * (u_int64_t)timeBase.numer / (u_int64_t)timeBase.denom) / (u_int64_t)1000000); +#else + static struct timeval bt; + static int initialized = 0; + + if (!initialized) { + struct utmpx* ut; + while (NULL != (ut = getutxent())) { + if (BOOT_TIME == ut->ut_type) { + memcpy(&bt, &ut->ut_tv, sizeof(struct timeval)); + break; + } + } + initialized = 1; + } + + struct timeval nt, btc; + (void)gettimeofday(&nt, NULL); + memcpy(&btc, &bt, sizeof(struct timeval)); + + if (nt.tv_usec < btc.tv_usec) { + u_int64_t n = (btc.tv_usec - nt.tv_usec) / 1000000 + 1; + btc.tv_usec -= 1000000 * n; + btc.tv_sec += n; + } + if (nt.tv_usec - btc.tv_usec > 1000000) { + u_int64_t n = (btc.tv_usec - nt.tv_usec) / 1000000; + btc.tv_usec += 1000000 * n; + btc.tv_sec -= n; + } + + nt.tv_usec = nt.tv_usec - btc.tv_usec; + nt.tv_sec = nt.tv_sec - btc.tv_sec; + + return (u_int32_t)((nt.tv_sec * 1000) + (nt.tv_usec / 1000)); +#endif +} + +int TFLCSWriteAMF3Integer(char* buffer, int value, int pos) +{ + if (value < 0) { + buffer[pos++] = (0x80 | ((value >> 22) & 0xff)); + buffer[pos++] = (0x80 | ((value >> 15) & 0x7f)); + buffer[pos++] = (0x80 | ((value >> 8) & 0x7f)); + buffer[pos++] = (value & 0xff); + } else if (value <= 0x7f) { + buffer[pos++] = value; + } else if (value <= 0x3fff) { + buffer[pos++] = (0x80 | ((value >> 7) & 0x7f)); + buffer[pos++] = (value & 0x7f); + } else if (value <= 0x1fffff) { + buffer[pos++] = (0x80 | ((value >> 14) & 0x7f)); + buffer[pos++] = (0x80 | ((value >> 7) & 0x7f)); + buffer[pos++] = (value & 0x7f); + } else { + buffer[pos++] = (0x80 | ((value >> 22) & 0xff)); + buffer[pos++] = (0x80 | ((value >> 15) & 0x7f)); + buffer[pos++] = (0x80 | ((value >> 8) & 0x7f)); + buffer[pos++] = (value & 0xff); + } + + return pos; +} + +int TFLCSWriteAMFString(char* buffer, const char * str, int pos) +{ + int len = strlen(str); + + buffer[pos++] = AMF_TYPE_STRING; + buffer[pos++] = 0; // TODO: string length is badly encoded here! + buffer[pos++] = (char)(len & 0xff); + + strcpy((char*)&buffer[pos], str); + + pos += len; + return pos; +} + +int TFLCSWriteAMF3ByteArray(char* buffer, const char* bytes, int pos, int len) +{ + // buffer[pos++] = AMF_TYPE_AMF3OBJ; + buffer[pos++] = AMF3_TYPE_BYTEARRAY; // AMF3_TYPE_BYTE_ARRAY + + pos = TFLCSWriteAMF3Integer(buffer, ((len << 1) | 1), pos); + + int i=0; + for(i=0; idata[AMF_ENVELOPE_TIMESTAMP_POS]; + + int pos = AMF_ENVELOPE_LEN; + // check timestamp and size + + memset(connection->data, 0, AMF_ENVELOPE_LEN); + + connection->data[0] = 1; + connection->data[4] = 1; + + *timestamp = TFLCSGetTickCount(); + + // write connection name + pos = TFLCSWriteAMFString(connection->data, connection->listenerName, pos); + // write protocol + pos = TFLCSWriteAMFString(connection->data, PROTOCOL_NAME, pos); + + // I have no idea what this is, but we apparently need it... + char weirdBytes[] = { + 0x01, 0x01, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x40, 0x24, 0, 0, 0, 0, 0, 0, 0, 0x40, 0x08, 0, 0, + 0, 0, 0, 0}; + int i; + for (i=0; i<31; i++) + connection->data[pos++] = weirdBytes[i]; + + // write method name + pos = TFLCSWriteAMFString(connection->data, connection->listenerMethod, pos); + + return pos; +} + +int TFLCSWriteLCAMFEnvelopeTrailer(TFLCSLocalConnection_t* connection, int pos) +{ + if (NULL == connection) + return pos; + + u_int32_t* size = (u_int32_t*)&connection->data[AMF_ENVELOPE_SIZE_POS]; + + //pos = writeAMF3ByteArray(buffer, msg, pos, strlen(msg)); + *size = pos-16; + + return pos; +} + +int TFLCSSendByteArray(TFLCSLocalConnection_t* connection, const char* bytes, int len) +{ + ENSURE_CONNECTION_UP(connection, 0); + + if (NULL == bytes || 0 == len || !_TFLCSConnectionStructureIsValidForUse(connection)) { + TFLCSErrno = TFLCSErrorInvalidArgument; + return 0; + } + + _TFLCSLockSemaphore(connection); + + int pos = TFLCSWriteLCAMFEnvelopeHeader(connection); + pos = TFLCSWriteAMF3ByteArray(connection->data, bytes, pos, len); + (void)TFLCSWriteLCAMFEnvelopeTrailer(connection, pos); + + _TFLCSUnlockSemaphore(connection); + + return 1; +} + +void TFLCSDumpMemory(char* buffer, int offset, int size) +{ + int i = 0; + int c = 0; + char b; + + while (i < size) { + while ((c < 16) && (i+c < size)) { + b = buffer[offset+i+c]; + printf("%X%X ", b/16 & 0x0f, b & 0x0f ); + c++; + } + + while (c++ < 16) + printf(" "); + + c = 0; + + while ((c < 16) && (i+c < size)) { + b = buffer[offset+i+c]; + if (b > 31) + printf("%c", (char)b); + else + printf("."); + c++; + } + + i += 16; + c = 0; + printf("\n"); + } +} + +void _TFLCSLockSemaphore(TFLCSLocalConnection_t* connection) +{ + if (NULL != connection) { +#if defined(WIN32) + if (NULL != connection->semaphore) + WaitForSingleObject(connection->semaphore, INFINITE); +#else + if ((sem_t*)SEM_FAILED != connection->semaphore) + sem_wait(connection->semaphore); +#endif + } +} + +void _TFLCSUnlockSemaphore(TFLCSLocalConnection_t* connection) +{ + if (NULL != connection) { +#if defined(WIN32) + if (NULL != connection->semaphore) + ReleaseMutex(connection->semaphore); +#else + if ((sem_t*)SEM_FAILED != connection->semaphore) + sem_post(connection->semaphore); +#endif + } +} + +int _TFLCSConnectionStructureIsValidForUse(TFLCSLocalConnection_t* connection) +{ + return (NULL != connection + && 0 != connection->open +#if defined(WIN32) + && NULL != connection->semaphore + && NULL != connection->mapFile + && NULL != connection->mapAddress + && NULL != connection->data +#else + && (sem_t*)SEM_FAILED != connection->semaphore + && (char*)-1 != connection->data +#endif + ); +} + +int _TFLCSDelayedConnect(TFLCSLocalConnection_t* connection) +{ +#if defined(WIN32) + if (NULL == connection) + return 0; + if (connection->open) + return 1; + + if (NULL == (connection->semaphore = OpenMutex(MUTEX_ALL_ACCESS, + FALSE, + WIN32_SEMAPHORE_NAME))) { + TFLCSErrno = TFLCSErrorSemaphoreCreationFailed; + goto errorReturn; + } + + if (NULL == (connection->mapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, + FALSE, + WIN32_SHMEM_NAME))) { + TFLCSErrno = TFLCSErrorShmemIDNotFound; + goto errorReturn; + } + + if (NULL == (connection->mapAddress = MapViewOfFile(connection->mapFile, + FILE_MAP_ALL_ACCESS, + 0, + 0, + 0))) { + TFLCSErrno = TFLCSErrorShmemOpeningFailed; + goto errorReturn; + } + + connection->data = (char*)connection->mapAddress; + connection->open = 1; + +errorReturn: +#endif + + return connection->open; +} + +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +using namespace TUIO2; + +FlashSender::FlashSender() { + local = true; + buffer_size = MAX_FLASH_SIZE; + lcConnection = TFLCSConnect(DEFAULT_LC_CONN_NAME,DEFAULT_LC_METH_NAME,NULL,NULL); + std::cout << "TUIO/FLC "<< DEFAULT_LC_METH_NAME << "@" << DEFAULT_LC_CONN_NAME << std::endl; +} + +FlashSender::FlashSender(const char *conn_name, const char *meth_name) { + local = true; + buffer_size = MAX_FLASH_SIZE; + lcConnection = TFLCSConnect(conn_name,meth_name,NULL,NULL); + std::cout << "TUIO/FLC "<< meth_name << "@" << conn_name << std::endl; +} + +FlashSender::~FlashSender() { + TFLCSDisconnect(lcConnection); +} + +bool FlashSender::isConnected() { + if (TFLCSConnectionHasConnectedClient(lcConnection)) return true; + else return false; +} + +bool FlashSender::sendOscPacket (osc::OutboundPacketStream *bundle) { + if (lcConnection==NULL)return false; + if (!TFLCSConnectionHasConnectedClient(lcConnection))return false; + if ( bundle->Size() > buffer_size ) return false; + if ( bundle->Size() == 0 ) return false; + + TFLCSSendByteArray(lcConnection, bundle->Data(), bundle->Size()); + return true; +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/FlashSender.h b/modules/touch/ext/libTUIO2/TUIO2/FlashSender.h new file mode 100644 index 0000000000..c584f8908e --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/FlashSender.h @@ -0,0 +1,215 @@ +// +// TFFlashLCSHMEM.h +// Touché +// +// Created by Georg Kaindl on 16/3/09. +// +// Copyright (C) 2009 Georg Kaindl +// +// This file is part of Touché. +// +// Touché is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// Touché is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with Touché. If not, see . + + +#if !defined(__TFFlashLCSHMEM_H__) +#define __TFFlashLCSHMEM_H__ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +#ifdef WIN32 +#include +typedef DWORD u_int32_t; +#else +#include +#include +#endif + +#define TFLCS_LISTENER_NAME_MAX_LEN (64) +#define TFLCS_LISTENER_METHOD_MAX_LEN (64) + + typedef struct TFLCSLocalConnection_t { +#ifdef WIN32 + HANDLE semaphore; + HANDLE mapFile; + LPVOID mapAddress; +#else + int shmid; + sem_t* semaphore; +#endif + int open; + char* data; + char listenerName[TFLCS_LISTENER_NAME_MAX_LEN]; + char listenerMethod[TFLCS_LISTENER_METHOD_MAX_LEN]; + } TFLCSLocalConnection_t; + + typedef enum { + TFLCSErrorSuccess = 0, + TFLCSErrorInvalidArgument = 1, + TFLCSErrorShmemKeyNotFound = 2, + TFLCSErrorSemaphoreCreationFailed = 3, + TFLCSErrorShmemIDNotFound = 4, + TFLCSErrorShmemOpeningFailed = 5, + TFLCSErrorOutOfMemory = 6 + } TFLCSError_t; + + // much like errno, this will hold the last error that happened + extern TFLCSError_t TFLCSErrno; + + // connect to a Flash LocalConnection + // returns pointer to structure on success, NULL otherwise + // if the connection could not be opened right away (because Flash is not yet running), + // a non-null pointer is returned, but the "open" member of the structure will be 0 + // and TFLCSErrno will be set accordingly. the connection is truly open once "open" is + // non-zero. + TFLCSLocalConnection_t* TFLCSConnect(const char* listenerName, + const char* listenerMethod, + void* shmemKey, + void* semaphoreKey); + + // disconnect a Flash LocalConnection + void TFLCSDisconnect(TFLCSLocalConnection_t* connection); + + // changes the connection listener name + void TFLCSChangeListenerName(TFLCSLocalConnection_t* connection, const char* newListenerName); + + // changes the connection method name + void TFLCSChangeMethodName(TFLCSLocalConnection_t* connection, const char* newMethodName); + + // returns non-zero if the given connection's Flash client is connected, 0 otherwise + int TFLCSConnectionHasConnectedClient(TFLCSLocalConnection_t* connection); + + // tries to determine the key for the shared memory region used by the Flash LocalConnection + // returns a pointer to static memory on success, NULL on error. + void* TFLCSGuessShmemKey(); + + // get the current tick count (milliseconds since the system was started) + u_int32_t TFLCSGetTickCount(); + + // write an AMF3-encoded integer into a buffer + // returns the updated buffer position + int TFLCSWriteAMF3Integer(char* buffer, int value, int pos); + + // write an AMF-encoded string into a buffer + // returns the updated buffer position + int TFLCSWriteAMFString(char* buffer, const char * str, int pos); + + // write an AMF3-encoded byte array into a buffer + // returns the updated buffer position + int TFLCSWriteAMF3ByteArray(char* buffer, const char* bytes, int pos, int len); + + // writes the AMF envelope header for an LC method call + // returns the position in the buffer + int TFLCSWriteLCAMFEnvelopeHeader(TFLCSLocalConnection_t* connection); + + // writes the AMF envelope trailer for an LC method call + // returns the updated buffer position + int TFLCSWriteLCAMFEnvelopeTrailer(TFLCSLocalConnection_t* connection, int pos); + + // sends the given data of length len over the given connection as a ByteArray + // returns 1 on success, 0 otherwise + int TFLCSSendByteArray(TFLCSLocalConnection_t* connection, const char* bytes, int len); + + // gets the (string) names of all connected LC connections + // returns the number of found strings. + int TFLCSGetConnectedConnectionNames(TFLCSLocalConnection_t* connection, char* dest, int destLen); + + // dumps a given buffer (size bytes starting at offset) to stdout in a nice hex/ascii format. + // useful for debugging purposes. + void TFLCSDumpMemory(char* buffer, int offset, int size); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif //__TFFlashLCSHMEM_H__ + +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_FLASHSENDER_H +#define INCLUDED_FLASHSENDER_H + +#include "OscSender.h" + +#define MAX_FLASH_SIZE (40976) +#define DEFAULT_LC_CONN_NAME "_OscDataStream" +#define DEFAULT_LC_METH_NAME "receiveOscData" + +namespace TUIO2 { + + /** + * The FlashSender implements the Flash LocalConnection transport method for OSC + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL FlashSender : public OscSender { + + public: + + /** + * The default constructor creates a FlashSender using a Flash LocalConnection on localhost + */ + FlashSender(); + + /** + * The default constructor creates a FlashSender using a Flash LocalConnection on localhost + */ + FlashSender(const char *conn_name, const char *meth_name); + + /** + * The destructor closes the connection. + */ + virtual ~FlashSender(); + + /** + * This method delivers the provided OSC data + * + * @param *bundle the OSC stream to deliver + * @return true if the data was delivered successfully + */ + + bool sendOscPacket (osc::OutboundPacketStream *bundle); + + /** + * This method returns the connection state + * + * @return true if the connection is alive + */ + bool isConnected (); + + const char* tuio_type() { return "TUIO/FLC"; } + + private: + TFLCSLocalConnection_t* lcConnection; + }; +} +#endif /* INCLUDED_FLASHSENDER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/LibExport.h b/modules/touch/ext/libTUIO2/TUIO2/LibExport.h new file mode 100644 index 0000000000..deab0f1ccd --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/LibExport.h @@ -0,0 +1,36 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_LIBEXPORT_H +#define INCLUDED_LIBEXPORT_H + +#ifdef WIN32 + #pragma warning(disable: 4251) // disable annoying template exporting warnings + #pragma warning(disable: 4275) // disable warning caused by not exported OSC classes + + #ifdef LIB_EXPORT + #define LIBDECL __declspec(dllexport) + #else +// #define LIBDECL __declspec(dllimport) + #define LIBDECL + #endif +#else + #define LIBDECL +#endif + +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.cpp b/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.cpp new file mode 100644 index 0000000000..0e9af08f47 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.cpp @@ -0,0 +1,60 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "OscReceiver.h" + +using namespace TUIO2; +using namespace osc; + +void OscReceiver::ProcessMessage( const ReceivedMessage& msg, const IpEndpointName& remoteEndpoint) { + for (std::list::iterator client=clientList.begin(); client!= clientList.end(); client++) + (*client)->processOSC(msg); +} + +void OscReceiver::ProcessBundle( const ReceivedBundle& b, const IpEndpointName& remoteEndpoint) { + try { + for( ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ + if( i->IsBundle() ) + ProcessBundle( ReceivedBundle(*i), remoteEndpoint); + else + ProcessMessage( ReceivedMessage(*i), remoteEndpoint); + } + } catch (MalformedBundleException& e) { + std::cerr << "malformed OSC bundle: " << e.what() << std::endl; + } + +} + +void OscReceiver::ProcessPacket( const char *data, int size, const IpEndpointName& remoteEndpoint ) { + try { + ReceivedPacket p( data, size ); + if(p.IsBundle()) ProcessBundle( ReceivedBundle(p), remoteEndpoint); + else ProcessMessage( ReceivedMessage(p), remoteEndpoint); + } catch (MalformedBundleException& e) { + std::cerr << "malformed OSC bundle: " << e.what() << std::endl; + } +} + +bool OscReceiver::isConnected() { + return connected; +} + +void OscReceiver::addTuioClient(TuioClient *client) { + clientList.push_back(client); +} + diff --git a/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.h b/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.h new file mode 100644 index 0000000000..b8bcd22743 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.h @@ -0,0 +1,97 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_OSCRECEIVER_H +#define INCLUDED_OSCRECEIVER_H + +#include "LibExport.h" +#include "TuioClient.h" + +#include "oscpack/osc/OscReceivedElements.h" +#include "oscpack/osc/OscHostEndianness.h" +#include "oscpack/ip/PacketListener.h" +#include "oscpack/ip/IpEndpointName.h" + +namespace TUIO2 { + + class TuioClient; // Forward declaration + + /** + * The OscReceiver is the base class for the various OSC transport methods such as UDP, TCP ... + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL OscReceiver: public PacketListener { + + public: + + /** + * The constructor is doing nothing in particular. + */ + OscReceiver() : connected(false) {}; + + /** + * The destructor is doing nothing in particular. + */ + virtual ~OscReceiver() {}; + + /** + * The OscReceiver connects and starts receiving TUIO messages via OSC + * + * @param lock running in the background if set to false (default) + */ + virtual void connect(bool lock=false) = 0; + + /** + * The OscReceiver disconnects and stops receiving TUIO messages via OSC + */ + virtual void disconnect() = 0; + + /** + * Returns true if this OscReceiver is currently connected. + * @return true if this OscReceiver is currently connected + */ + bool isConnected(); + + /** + * Attaches the provided TuioClient to this OscReceiver + * + * @param client a pointer to the TuioClient to attach + */ + void addTuioClient(TuioClient *client); + + /** + * The OSC callback method where the incoming OSC data is received + * + * @param data the received OSC data + * @param size the size of the received OSC data + * @param remoteEndpoint the origin of the received OSC data + */ + void ProcessPacket( const char *data, int size, const IpEndpointName &remoteEndpoint ); + + protected: + void ProcessBundle( const osc::ReceivedBundle& b, const IpEndpointName& remoteEndpoint); + + void ProcessMessage( const osc::ReceivedMessage& message, const IpEndpointName& remoteEndpoint); + + std::list clientList; + bool connected; + }; +}; +#endif /* INCLUDED_OSCRECEIVER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/OscSender.h b/modules/touch/ext/libTUIO2/TUIO2/OscSender.h new file mode 100644 index 0000000000..967941ca5b --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/OscSender.h @@ -0,0 +1,90 @@ +/* + TUIO2 C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_OSCSENDER_H +#define INCLUDED_OSCSENDER_H + +#include "LibExport.h" +#include "oscpack/osc/OscOutboundPacketStream.h" +#include "oscpack/osc/OscHostEndianness.h" +#include "oscpack/ip/NetworkingUtils.h" +#include +#include + +namespace TUIO2 { + + /** + * The OscSender class is the base class for the various OSC transport methods such as UDP, TCP ... + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL OscSender { + + public: + + /** + * The constructor is doing nothing in particular. + */ + OscSender (): local(true) {}; + + /** + * The destructor is doing nothing in particular. + */ + virtual ~OscSender() {} + + /** + * This method delivers the provided OSC data + * + * @param *bundle the OSC stream to deliver + * @return true if the data was delivered successfully + */ + virtual bool sendOscPacket (osc::OutboundPacketStream *bundle) = 0; + + /** + * This method returns the connection state + * + * @return true if the connection is alive + */ + virtual bool isConnected () = 0; + + /** + * This method returns if this OscSender delivers locally + * + * @return true if this OscSender delivers locally + */ + bool isLocal () { return local; }; + + /** + * This method returns the maximum bundle size in bytes + * + * @return the maximum bundle size in bytes + */ + int getBufferSize () { return buffer_size; }; + + virtual const char* tuio_type() = 0; + + protected: + unsigned int buffer_size; + bool local; + }; +} + + +#endif /* INCLUDED_OSCSENDER_H */ + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp b/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp new file mode 100644 index 0000000000..ba0a5f4c65 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp @@ -0,0 +1,264 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TcpReceiver.h" + +using namespace TUIO2; +using namespace osc; + +// workaround for connect method name conflict +int tcp_connect(int socket, const struct sockaddr *address, socklen_t address_len) { + return connect(socket, address, address_len); +} + +#if defined (WIN32) && not defined (int32_t) +typedef DWORD int32_t; +#endif + +#ifdef WIN32 +static DWORD WINAPI ClientThreadFunc( LPVOID obj ) +#else +static void* ClientThreadFunc( void* obj ) +#endif +{ + TcpReceiver *sender = static_cast(obj); + char data_buffer[MAX_TCP_SIZE+4]; + char data_size[4]; + +#ifdef WIN32 + SOCKET client = sender->tcp_client_list.back(); +#else + int client = sender->tcp_client_list.back(); +#endif + + int bytes = 1; + while (bytes) { + bytes = recv(client, data_buffer, sizeof(data_buffer),0); + + if (bytes>=4) { + memcpy(&data_size[0],&data_buffer[0], 4); +#ifdef OSC_HOST_LITTLE_ENDIAN + int32_t temp = (int32_t)(*data_size); + data_size[0] = temp>>24; + data_size[1] = (temp>>16) & 255; + data_size[2] = (temp>>8) & 255; + data_size[3] = (temp) & 255; +#endif + int32_t size = (int32_t)(*data_size); + if (size+4==bytes) { + sender->ProcessPacket(&data_buffer[4],(int)size,IpEndpointName()); + } + } + } + + sender->tcp_client_list.remove(client); + std::cout << "closed TUIO/TCP connection" << std::endl; + + //if (sender->tcp_client_list.size()==0) sender->connected=false; + //std::cout << sender->tcp_client_list.size() << " clients left"<< std::endl; + + return 0; +}; + +#ifndef WIN32 +static void* ServerThreadFunc( void* obj ) +#else +static DWORD WINAPI ServerThreadFunc( LPVOID obj ) +#endif +{ + TcpReceiver *sender = static_cast(obj); + struct sockaddr_in client_addr; + socklen_t len = sizeof(client_addr); + + while ((int)sender->tcp_socket>0) { +#ifdef WIN32 + SOCKET tcp_client = -1; +#else + int tcp_client = -1; +#endif + tcp_client = accept(sender->tcp_socket, (struct sockaddr*)&client_addr, &len); + + if (tcp_client>0) { + std::cout << "listening to TUIO/TCP messages from " << inet_ntoa(client_addr.sin_addr) << "@" << client_addr.sin_port << std::endl; + sender->tcp_client_list.push_back(tcp_client); + //sender->connected=true; + //std::cout << sender->tcp_client_list.size() << " clients connected"<< std::endl; + +#ifndef WIN32 + pthread_t client_thread; + pthread_create(&client_thread , NULL, ClientThreadFunc,obj); +#else + DWORD ClientThreadId; + HANDLE client_thread = CreateThread( 0, 0, ClientThreadFunc, obj, 0, &ClientThreadId ); +#endif + } else break; + + } + + return 0; +}; + +TcpReceiver::TcpReceiver(unsigned short port) +: tcp_socket (-1) +, locked (false) +{ + + tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (tcp_socket < 0) std::cerr << "could not create TUIO/TCP socket" << std::endl; + + int optval = 1; +#ifdef WIN32 + int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const char *)&optval, sizeof(int)); +#else + int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const void *)&optval, sizeof(int)); +#endif + if (ret < 0) { + std::cerr << "could not reuse TUIO/TCP socket address" << std::endl; + return; + } + + struct sockaddr_in tcp_server; + memset( &tcp_server, 0, sizeof (tcp_server)); + + tcp_server.sin_family = AF_INET; + tcp_server.sin_addr.s_addr = htonl(INADDR_ANY); + tcp_server.sin_port = htons(port); + + socklen_t len = sizeof(tcp_server); + ret = bind(tcp_socket,(struct sockaddr*)&tcp_server,len); + if (ret < 0) { + std::cerr << "could not bind to TUIO/TCP socket on port " << port << std::endl; + return; + } + + ret = listen(tcp_socket, 1); + if (ret < 0) { + std::cerr << "could not start listening to TUIO/TCP socket" << std::endl; +#ifdef WIN32 + closesocket(tcp_socket); +#else + close(tcp_socket); +#endif + tcp_socket=-1; + return; + } + + std::cout << "TUIO/TCP socket created on port " << port << std::endl; +} + +TcpReceiver::TcpReceiver(const char *host, unsigned short port) +: tcp_socket (-1) +, locked (false) +{ + + tcp_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (tcp_socket < 0) { + std::cerr << "could not create TUIO/TCP socket" << std::endl; + return; + } + + struct sockaddr_in tcp_server; + memset( &tcp_server, 0, sizeof (tcp_server)); + unsigned long addr = inet_addr(host); + if (addr != INADDR_NONE) { + memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr)); + } else { + struct hostent *host_info = gethostbyname(host); + if (host_info == NULL) std::cerr << "unknown host name: " << host << std::endl; + memcpy( (char *)&tcp_server.sin_addr, host_info->h_addr, host_info->h_length ); + } + + tcp_server.sin_family = AF_INET; + tcp_server.sin_port = htons(port); + + int ret = tcp_connect(tcp_socket,(struct sockaddr*)&tcp_server,sizeof(tcp_server)); + if (ret<0) { +#ifdef WIN32 + closesocket(tcp_socket); +#else + close(tcp_socket); +#endif + std::cerr << "could not connect to TUIO/TCP server at " << host << ":"<< port << std::endl; + tcp_socket=-1; + return; + } else { + tcp_client_list.push_back(tcp_socket); + std::cout << "listening to TUIO/TCP messages from " << host << ":" << port << std::endl; + } +} + +TcpReceiver::~TcpReceiver() { + +} + +void TcpReceiver::connect(bool lk) { + + if (connected) return; + if ((int)tcp_socket<0) return; + locked = lk; + + if (tcp_client_list.size()>0) { + if (!locked) { +#ifndef WIN32 + pthread_create(&server_thread , NULL, ClientThreadFunc, this); +#else + server_thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &ServerThreadId ); +#endif + } else ClientThreadFunc(this); + } else { + if (!locked) { +#ifndef WIN32 + pthread_create(&server_thread , NULL, ServerThreadFunc, this); +#else + server_thread = CreateThread( 0, 0, ServerThreadFunc, this, 0, &ServerThreadId ); +#endif + } else ServerThreadFunc(this); + } + + connected = true; +} + +void TcpReceiver::disconnect() { + + if (!connected) return; + if ((int)tcp_socket<0) return; + +#ifdef WIN32 + for (std::list::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) + closesocket((*client)); + closesocket(tcp_socket); + if( server_thread ) CloseHandle( server_thread ); +#else + for (std::list::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) + close((*client)); + close(tcp_socket); + server_thread = 0; +#endif + + tcp_client_list.clear(); + if (!locked) { +#ifdef WIN32 + if( server_thread ) CloseHandle( server_thread ); +#endif + server_thread = 0; + } else locked = false; + + connected = false; +} + + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.h b/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.h new file mode 100644 index 0000000000..75816b5e8e --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.h @@ -0,0 +1,102 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TCPRECEIVER_H +#define INCLUDED_TCPRECEIVER_H + +#include "OscReceiver.h" +#define MAX_TCP_SIZE 65536 + +#ifdef WIN32 +#include +#include +typedef int socklen_t; +#else +#include +#include +#include +#include +#include +#include +#endif + +namespace TUIO2 { + + /** + * The TcpReceiver provides the OscReceiver functionality for the TCP transport method + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TcpReceiver: public OscReceiver { + + public: + + /** + * This constructor creates a TcpReceiver instance listening to the provided TCP port + * + * @param port the number of the TCP port to listen to, defaults to 3333 + */ + TcpReceiver (unsigned short port=3333); + + /** + * This constructor creates a TcpReceiver connected to the provided host and TCP port + * + * @param host the host name to connect + * @param port the number of the TCP port to listen to, defaults to 3333 + */ + TcpReceiver (const char *host, unsigned short port); + + /** + * The destructor is doing nothing in particular. + */ + virtual ~TcpReceiver(); + + /** + * The TcpReceiver connects and starts receiving TUIO messages via TCP + * + * @param lock running in the background if set to false (default) + */ + void connect(bool lock=false); + + /** + * The TcpReceiver disconnects and stops receiving TUIO messages via TCP + */ + void disconnect(); + +#ifndef WIN32 + int tcp_socket; + std::list tcp_client_list; +#else + SOCKET tcp_socket; + std::list tcp_client_list; +#endif + + private: + +#ifndef WIN32 + pthread_t server_thread; +#else + HANDLE server_thread; + DWORD ServerThreadId; +#endif + + bool locked; + }; +}; +#endif /* INCLUDED_TcpReceiver_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpSender.cpp b/modules/touch/ext/libTUIO2/TUIO2/TcpSender.cpp new file mode 100644 index 0000000000..d6a3acc597 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TcpSender.cpp @@ -0,0 +1,303 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TcpSender.h" +using namespace TUIO2; + +#ifndef WIN32 +static void* ClientThreadFunc( void* obj ) +#else +static DWORD WINAPI ClientThreadFunc( LPVOID obj ) +#endif +{ + TcpSender *sender = static_cast(obj); + char buf[16]; + +#ifdef WIN32 + SOCKET client = sender->tcp_client_list.back(); +#else + int client = sender->tcp_client_list.back(); +#endif + + int connected = 1; + while (connected) { + connected = recv(client, buf, sizeof(buf),0); + } + + sender->tcp_client_list.remove(client); + std::cout << sender->tuio_type() << " connection closed"<< std::endl; + if (sender->tcp_client_list.size()==0) sender->connected=false; + //std::cout << sender->tcp_client_list.size() << " clients left"<< std::endl; + + return 0; +}; + +#ifndef WIN32 +static void* ServerThreadFunc( void* obj ) +#else +static DWORD WINAPI ServerThreadFunc( LPVOID obj ) +#endif +{ + TcpSender *sender = static_cast(obj); + struct sockaddr_in client_addr; + socklen_t len = sizeof(client_addr); + + std::cout << sender->tuio_type() << " socket created on port " << sender->port_no << std::endl; + while (sender->tcp_socket) { +#ifdef WIN32 + SOCKET tcp_client = -1; +#else + int tcp_client = -1; +#endif + + tcp_client = accept(sender->tcp_socket, (struct sockaddr*)&client_addr, &len); +#ifdef WIN32 + //win32 workaround on exit + if (!client_addr.sin_addr.S_un.S_addr && !client_addr.sin_port) return 0; + if ((client_addr.sin_addr.S_un.S_addr==3435973836) && (client_addr.sin_port==52428)) return 0; +#endif + + if (tcp_client>0) { + std::cout << sender->tuio_type() << " client connected from " << inet_ntoa(client_addr.sin_addr) << "@" << client_addr.sin_port << std::endl; + sender->tcp_client_list.push_back(tcp_client); + sender->connected=true; + sender->newClient(tcp_client); + //std::cout << sender->tcp_client_list.size() << " clients connected"<< std::endl; +#ifndef WIN32 + pthread_t client_thread; + pthread_create(&client_thread , NULL, ClientThreadFunc,obj); +#else + DWORD ClientThreadId; + HANDLE client_thread = CreateThread( 0, 0, ClientThreadFunc, obj, 0, &ClientThreadId ); +#endif + } else break; + } + + return 0; +}; + +TcpSender::TcpSender() + :connected (false) +{ + local = true; + buffer_size = MAX_TCP_SIZE; + + tcp_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + if (tcp_socket < 0) { + std::cerr << "could not create " << tuio_type() << " socket" << std::endl; + return; + } + + struct sockaddr_in tcp_server; + memset( &tcp_server, 0, sizeof (tcp_server)); + //unsigned long addr = inet_addr("127.0.0.1"); + //memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr)); + + tcp_server.sin_family = AF_INET; + tcp_server.sin_port = htons(3333); + tcp_server.sin_addr.s_addr = inet_addr("127.0.0.1"); + + int ret = connect(tcp_socket,(struct sockaddr*)&tcp_server,sizeof(tcp_server)); + if (ret<0) { + std::cerr << "could not open " << tuio_type() << " connection to 127.0.0.1:3333" << std::endl; + return; + } else { + std::cout << tuio_type() << " connection opened to 127.0.0.1:3333" << std::endl; + tcp_client_list.push_back(tcp_socket); + connected = true; + +#ifndef WIN32 + pthread_create(&server_thread , NULL, ClientThreadFunc,this); +#else + HANDLE server_thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &ServerThreadId ); +#endif + + } + +} + +TcpSender::TcpSender(const char *host, int port) + :connected (false) +{ + if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) { + local = true; + } else local = false; + buffer_size = MAX_TCP_SIZE; + + tcp_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + if (tcp_socket < 0) { + std::cerr << "could not create " << tuio_type() << " socket" << std::endl; + return; + } + + struct sockaddr_in tcp_server; + memset( &tcp_server, 0, sizeof (tcp_server)); + unsigned long addr = inet_addr(host); + if (addr != INADDR_NONE) { + memcpy( (char *)&tcp_server.sin_addr, &addr, sizeof(addr)); + } else { + struct hostent *host_info = gethostbyname(host); + if (host_info == NULL) { + std::cerr << "unknown host name: " << host << std::endl; + throw std::exception(); + } + memcpy( (char *)&tcp_server.sin_addr, host_info->h_addr, host_info->h_length ); + } + + tcp_server.sin_family = AF_INET; + tcp_server.sin_port = htons(port); + + int ret = connect(tcp_socket,(struct sockaddr*)&tcp_server,sizeof(tcp_server)); + if (ret<0) { +#ifdef WIN32 + closesocket(tcp_socket); +#else + close(tcp_socket); +#endif + std::cerr << "could not open " << tuio_type() << " connection to " << host << ":"<< port << std::endl; + throw std::exception(); + } else { + std::cout << tuio_type() << " connection opened to " << host << ":"<< port << std::endl; + tcp_client_list.push_back(tcp_socket); + connected = true; + +#ifndef WIN32 + pthread_create(&server_thread , NULL, ClientThreadFunc,this); +#else + HANDLE server_thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &ServerThreadId ); +#endif + + } +} + +TcpSender::TcpSender(int port) + :connected (false) +{ + local = false; + buffer_size = MAX_TCP_SIZE; + port_no = port; + + tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (tcp_socket < 0) { + std::cerr << "could not create TUIO/TCP socket" << std::endl; + throw std::exception(); + } + + int optval = 1; + #ifdef WIN32 + int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const char *)&optval, sizeof(int)); + #else + int ret = setsockopt(tcp_socket,SOL_SOCKET,SO_REUSEADDR, (const void *)&optval, sizeof(int)); + #endif + if (ret < 0) { + std::cerr << "could not reuse TUIO/TCP socket address" << std::endl; + throw std::exception(); + } + + struct sockaddr_in tcp_server; + memset( &tcp_server, 0, sizeof (tcp_server)); + + tcp_server.sin_family = AF_INET; + tcp_server.sin_addr.s_addr = htonl(INADDR_ANY); + tcp_server.sin_port = htons(port); + + socklen_t len = sizeof(tcp_server); + ret = bind(tcp_socket,(struct sockaddr*)&tcp_server,len); + if (ret < 0) { + std::cerr << "could not bind to TUIO/TCP socket on port " << port << std::endl; + throw std::exception(); + } + + ret = listen(tcp_socket, 1); + if (ret < 0) { + std::cerr << "could not start listening to TUIO/TCP socket" << std::endl; +#ifdef WIN32 + closesocket(tcp_socket); +#else + close(tcp_socket); +#endif + throw std::exception(); + } + +#ifndef WIN32 + pthread_create(&server_thread , NULL, ServerThreadFunc, this); +#else + DWORD ServerThreadId; + server_thread = CreateThread( 0, 0, ServerThreadFunc, this, 0, &ServerThreadId ); +#endif + +} + +bool TcpSender::isConnected() { + return connected; +} + + +TcpSender::~TcpSender() { +#ifdef WIN32 + + for (std::list::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) { + closesocket((*client)); + } + closesocket(tcp_socket); + + if( server_thread ) CloseHandle( server_thread ); + +#else + for (std::list::iterator client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) { + close((*client)); + } + close(tcp_socket); + tcp_socket = 0; + server_thread = 0; +#endif +} + + +bool TcpSender::sendOscPacket (osc::OutboundPacketStream *bundle) { + if (!connected) return false; + if ( bundle->Size() > buffer_size ) return false; + if ( bundle->Size() == 0 ) return false; + +#ifdef OSC_HOST_LITTLE_ENDIAN + data_size[0] = bundle->Size()>>24; + data_size[1] = (bundle->Size()>>16) & 255; + data_size[2] = (bundle->Size()>>8) & 255; + data_size[3] = (bundle->Size()) & 255; +#else + *((int32_t*)data_size) = bundle->Size(); +#endif + +#ifdef WIN32 + std::list::iterator client; +#else + std::list::iterator client; +#endif + + for (client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) { + //send((*client), data_size, 4,0); + //send((*client), bundle->Data(), bundle->Size(),0); + memcpy(&data_buffer[0], &data_size, 4); + memcpy(&data_buffer[4], bundle->Data(), bundle->Size()); + send((*client),data_buffer, 4+bundle->Size(),0); + } + + return true; +} + +void TcpSender::newClient( int tcp_client ) { } diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpSender.h b/modules/touch/ext/libTUIO2/TUIO2/TcpSender.h new file mode 100644 index 0000000000..03b8678048 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TcpSender.h @@ -0,0 +1,126 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TCPSENDER_H +#define INCLUDED_TCPSENDER_H + +#include "OscSender.h" + +#ifdef WIN32 +#include +#include +typedef int socklen_t; +#else +#include +#include +#include +#include +#include +#include +#endif + +#include +#define MAX_TCP_SIZE 65536 + +namespace TUIO2 { + + /** + * The TcpSender implements the TCP transport method for OSC + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TcpSender : public OscSender { + + public: + + /** + * The default constructor creates a TcpSender that sends to the default TUIO port 3333 on localhost + */ + TcpSender(); + + /** + * This constructor creates a TcpSender that sends to the provided port on the the given host + * + * @param host the receiving host name + * @param port the outgoing TUIO TCP port number + */ + TcpSender(const char *host, int port); + + /** + * This constructor creates a TcpSender that listens to the provided port + * + * @param port the incoming TUIO TCP port number + */ + TcpSender(int port); + + /** + * The destructor closes the socket. + */ + virtual ~TcpSender(); + + /** + * This method delivers the provided OSC data + * + * @param *bundle the OSC stream to deliver + * @return true if the data was delivered successfully + */ + + bool sendOscPacket (osc::OutboundPacketStream *bundle); + + /** + * This method returns the connection state + * + * @return true if the connection is alive + */ + bool isConnected (); + + /** + * This method is called whenever a new client connects + * + * @param tcp_client the socket handle of the new client + */ + virtual void newClient( int tcp_client ); + + int port_no; + +#ifdef WIN32 + SOCKET tcp_socket; + std::list tcp_client_list; +#else + int tcp_socket; + std::list tcp_client_list; +#endif + bool connected; + const char* tuio_type() { return "TUIO/TCP"; } + + protected: + char data_size[4]; + char data_buffer[MAX_TCP_SIZE+4]; + + +#ifdef WIN32 + HANDLE server_thread; + DWORD ServerThreadId; +#else + pthread_t server_thread; +#endif + + }; +} +#endif /* INCLUDED_TCPSENDER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp new file mode 100644 index 0000000000..bf2f1c8002 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp @@ -0,0 +1,94 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioBounds.h" +using namespace TUIO2; + +TuioBounds::TuioBounds (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a, float w, float h, float f):TuioComponent(ttime, tobj, xp, yp,a) { + width = w; + height = h; + area = f; +} + +TuioBounds::TuioBounds (TuioObject *tobj, float xp, float yp, float a, float w, float h, float f):TuioComponent(tobj, xp, yp, a) { + width = w; + height = h; + area = f; +} + +TuioBounds::TuioBounds (TuioBounds *tbnd):TuioComponent(tbnd) { + angle = tbnd->getAngle(); + width = tbnd->getWidth(); + height = tbnd->getHeight(); + area = tbnd->getArea(); + rotation_speed = 0.0f; + rotation_accel = 0.0f; +} + +void TuioBounds::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { + TuioComponent::update(ttime,xp,yp,a,xs,ys,rs,ma,ra); + width = w; + height = h; + area = f; +} + +void TuioBounds::update (float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { + TuioComponent::update(xp,yp,a,xs,ys,rs,ma,ra); + width = w; + height = h; + area = f; +} + +void TuioBounds::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f) { + TuioComponent::update(ttime,xp,yp,a); + + width = w; + height = h; + area = f; +} + +void TuioBounds::stop (TuioTime ttime) { + update(ttime,xpos,ypos,angle,width,height,area); +} + +void TuioBounds::update (TuioBounds *tbnd) { + TuioComponent::update(tbnd); + width = tbnd->getWidth(); + height = tbnd->getHeight(); + area = tbnd->getArea(); +} + +float TuioBounds::getWidth() const{ + return width; +} + +float TuioBounds::getHeight() const{ + return height; +} + +int TuioBounds::getScreenWidth(int w) const{ + return (int)(w*width); +} + +int TuioBounds::getScreenHeight(int h) const{ + return (int)(h*height); +} + +float TuioBounds::getArea() const{ + return area; +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h b/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h new file mode 100644 index 0000000000..803f67c3b7 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h @@ -0,0 +1,206 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOBOUNDS_H +#define INCLUDED_TUIOBOUNDS_H + +#include "TuioComponent.h" + +namespace TUIO2 { + + /** + * The TuioBounds class encapsulates /tuio2/bnd TUIO boundary ellipses. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + + class LIBDECL TuioBounds: public TuioComponent { + + protected: + /** + * The rotation angle value. + */ + float angle; + /** + * The width value. + */ + float width; + /** + * The height value. + */ + float height; + /** + * The area value. + */ + float area; + /** + * The rotation speed value. + */ + float rotation_speed; + /** + * The rotation acceleration value. + */ + float rotation_accel; + + public: + using TuioComponent::update; + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, X and Y coordinate, width, height and angle to the newly created TuioBounds. + * + * @param ttime the TuioTime to assign + * @param tobj the TuioObject to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param w the width to assign + * @param h the height to assign + * @param f the area to assign + */ + TuioBounds (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a, float w, float h, float f); + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, X and Y coordinate, width, height and angle to the newly created TuioBounds. + * + * @param tobj the TuioObject to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param w the width to assign + * @param h the height to assign + * @param f the area to assign + */ + TuioBounds (TuioObject *tobj, float xp, float yp, float a, float w, float h, float f); + + /** + * This constructor takes the atttibutes of the provided TuioBounds + * and assigs these values to the newly created TuioBounds. + * + * @param tbnd the TuioBounds to assign + */ + TuioBounds (TuioBounds *tbnd); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioBounds() {}; + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate, angle, X and Y velocity, motion acceleration, + * rotation speed and rotation acceleration to the private TuioBounds attributes. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param w the width to assign + * @param h the height to assign + * @param f the area to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param rs the rotation velocity to assign + * @param ma the motion acceleration to assign + * @param ra the rotation acceleration to assign + */ + void update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra); + + /** + * Assigns the provided X and Y coordinate, angle, X and Y velocity, motion acceleration + * rotation velocity and rotation acceleration to the private TuioComponent attributes. + * The TuioTime time stamp remains unchanged. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param w the width to assign + * @param h the height to assign + * @param f the area to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param rs the rotation velocity to assign + * @param ma the motion acceleration to assign + * @param ra the rotation acceleration to assign + */ + void update (float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra); + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate and angle to the private TuioBounds attributes. + * The speed and accleration values are calculated accordingly. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle coordinate to assign + * @param w the width to assign + * @param h the height to assign + * @param f the area to assign + */ + void update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f); + + /** + * This method is used to calculate the speed and acceleration values of a + * TuioBounds with unchanged position and angle. + */ + void stop (TuioTime ttime); + + /** + * Takes the atttibutes of the provided TuioBounds + * and assigs these values to this TuioBounds. + * The TuioTime time stamp of this TuioComponent remains unchanged. + * + * @param tbnd the TuioComponent to assign + */ + void update (TuioBounds *tbnd); + + /** + * Returns the width of this TuioBounds. + * @return the width of this TuioBounds + */ + float getWidth() const; + + /** + * Returns the height of this TuioBounds. + * @return the height of this TuioBounds + */ + float getHeight() const; + + /** + * Returns the width of this TuioBounds. + * @return the width of this TuioBounds + */ + int getScreenWidth(int w) const; + + /** + * Returns the height of this TuioBounds. + * @return the height of this TuioBounds + */ + int getScreenHeight(int h) const; + + /** + * Returns the area of this TuioBounds. + * @return the area of this TuioBounds + */ + float getArea() const; + }; +} +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp new file mode 100644 index 0000000000..e638651008 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp @@ -0,0 +1,520 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioClient.h" +#include "UdpReceiver.h" + +using namespace TUIO2; +using namespace osc; + + +TuioClient::TuioClient() +: lateFrame (false) +, source_count (0) +, receiver (NULL) +, local_receiver(true) +{ + receiver = new UdpReceiver(); + initialize(); +} + +TuioClient::TuioClient(unsigned short port) +: lateFrame (false) +, source_count (0) +, receiver (NULL) +, local_receiver(true) +{ + receiver = new UdpReceiver(port); + initialize(); +} + +TuioClient::TuioClient(OscReceiver *osc) +: lateFrame (false) +, source_count (0) +, receiver (osc) +, local_receiver(false) +{ + initialize(); +} + +void TuioClient::initialize() { + receiver->addTuioClient(this); +} + +TuioClient::~TuioClient() { + if (local_receiver) delete receiver; +} + +void TuioClient::processOSC( const ReceivedMessage& msg ) { + try { + ReceivedMessageArgumentStream args = msg.ArgumentStream(); + //ReceivedMessage::const_iterator arg = msg.ArgumentsBegin(); + + if( strcmp( msg.AddressPattern(), "/tuio2/frm" ) == 0 ) { + //lockFrame(); + int32 fseq_raw,dim_raw; + TimeTag timetag; + const char* src_string; + args >> fseq_raw >> timetag >> dim_raw >> src_string; + + // check if we know that source + std::map::iterator iter = sourceList.find(src_string); + + if (iter==sourceList.end()) { // add a new source + frameSource = new TuioSource(source_count, src_string, (unsigned int)dim_raw); + sourceList[src_string] = frameSource; + source_count++; + } else { // use the found source + frameSource = sourceList[src_string]; + } + + unsigned int currentFrameID = (unsigned int)fseq_raw; + frameTime = TuioTime(timetag); + frameTime.setFrameID(currentFrameID); + + // frame sequence + lateFrame = false; + unsigned int lastFrameID = frameSource->getFrameTime().getFrameID(); + unsigned int timeDiff = frameTime.getTotalMilliseconds() - frameSource->getFrameTime().getTotalMilliseconds(); + frameSource->setFrameTime(frameTime); + + // drop late frames (but accept the reserved ID 0 and consider a possible reset after 1sec + if ((currentFrameID> s_id_raw >> tu_id_raw >> c_id_raw >> xpos >> ypos >> angle; + if (!args.Eos()) args >> xspeed >> yspeed >> rspeed >> maccel >> raccel; + else xspeed = yspeed = rspeed = maccel = raccel = 0.0f; + + s_id = (unsigned int)s_id_raw; + c_id = (unsigned int)c_id_raw; + t_id = tu_id_raw >> 16; + u_id = tu_id_raw & 0x0000FFFF; + + TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); + //if (tobj == NULL) std::cout << "new cont " << s_id << " " << frameSource.getSourceID() << std::endl; + if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); + addFrameObject(tobj); + TuioToken *ttok = tobj->getTuioToken(); + if (ttok == NULL) { + ttok = new TuioToken(frameTime,tobj,t_id,u_id,c_id,xpos,ypos,angle); + tobj->setTuioToken(ttok); + } else if ( (ttok->getX()!=xpos) || (ttok->getY()!=ypos) || (ttok->getAngle()!=angle) || (ttok->getXSpeed()!=xspeed) || (ttok->getYSpeed()!=yspeed) || (ttok->getRotationSpeed()!=rspeed) || (ttok->getMotionAccel()!=maccel) || (ttok->getRotationAccel()!=raccel) ) { + + ttok->update(frameTime,xpos,ypos,angle,xspeed,yspeed,rspeed,maccel,raccel); + } + + } else if( strcmp( msg.AddressPattern(), "/tuio2/ptr" ) == 0 ) { + + if (lateFrame) return; + int32 s_id_raw, tu_id_raw, c_id_raw; + unsigned short t_id, u_id; + unsigned int s_id,c_id; + float xpos, ypos, angle, shear,radius, pressure, xspeed, yspeed, pspeed, maccel, paccel; + args >> s_id_raw >> tu_id_raw >> c_id_raw >> xpos >> ypos >> angle >> shear >> radius >> pressure; + if (!args.Eos()) args >> xspeed >> yspeed >> pspeed >> maccel >> paccel; + else xspeed = yspeed = pspeed = maccel = paccel = 0.0f; + + s_id = (unsigned int)s_id_raw; + c_id = (unsigned int)c_id_raw; + t_id = tu_id_raw >> 16; + u_id = tu_id_raw & 0x0000FFFF; + + TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); + //if (tobj == NULL) std::cout << "new cont " << s_id << " " << frameSource.getSourceID() << std::endl; + if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); + addFrameObject(tobj); + TuioPointer *tptr = tobj->getTuioPointer(); + if (tptr == NULL) { + tptr = new TuioPointer(frameTime,tobj,t_id,u_id,c_id,xpos,ypos,angle,shear,radius,pressure); + tobj->setTuioPointer(tptr); + + } else if ( (tptr->getX()!=xpos) || (tptr->getY()!=ypos) || (tptr->getAngle()!=angle) || (tptr->getShear()!=shear) || (tptr->getRadius()!=radius) || (tptr->getPressure()!=pressure) || (tptr->getXSpeed()!=xspeed) || (tptr->getYSpeed()!=yspeed) || (tptr->getPressureSpeed()!=pspeed) || (tptr->getMotionAccel()!=maccel) || (tptr->getPressureAccel()!=paccel) ) { + + tptr->update(frameTime,xpos,ypos,angle,shear,radius,pressure,xspeed,yspeed,pspeed,maccel,paccel); + } + } else if( strcmp( msg.AddressPattern(), "/tuio2/bnd" ) == 0 ) { + + if (lateFrame) return; + int32 s_id_raw; + unsigned int s_id; + float xpos, ypos, angle, width, height, area; + float xspeed, yspeed, rspeed, maccel, raccel; + args >> s_id_raw >> xpos >> ypos >> angle >> width >> height >> area; + if (!args.Eos()) args >> xspeed >> yspeed >> rspeed >> maccel >> raccel; + else xspeed = yspeed = rspeed = maccel = raccel = 0.0f; + + s_id = (unsigned int)s_id_raw; + TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); + if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); + addFrameObject(tobj); + TuioBounds *tbnd = tobj->getTuioBounds(); + if (tbnd == NULL) { + tbnd = new TuioBounds(frameTime,tobj,xpos,ypos,angle,width,height,area); + tobj->setTuioBounds(tbnd); + } else if ( (tbnd->getX()!=xpos) || (tbnd->getY()!=ypos) || (tbnd->getAngle()!=angle) || (tbnd->getWidth()!=width) || (tbnd->getHeight()!=height) || (tbnd->getArea()!=area) || (tbnd->getXSpeed()!=xspeed) || (tbnd->getYSpeed()!=yspeed) || (tbnd->getRotationSpeed()!=rspeed) || (tbnd->getMotionAccel()!=maccel) || (tbnd->getRotationAccel()!=raccel)) { + + tbnd->update(frameTime,xpos,ypos,angle,width,height,area,xspeed,yspeed,rspeed,maccel,raccel); + } + } else if( strcmp( msg.AddressPattern(), "/tuio2/sym" ) == 0 ) { + + if (lateFrame) return; + int32 s_id_raw, tu_id_raw, c_id_raw; + unsigned int s_id, c_id; + unsigned short t_id, u_id; + const char* type; + const char* data; + args >> s_id_raw >> tu_id_raw >> c_id_raw >> type >> data; + + s_id = (unsigned int)s_id_raw; + c_id = (unsigned int)c_id_raw; + t_id = tu_id_raw >> 16; + u_id = tu_id_raw & 0x0000FFFF; + + TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); + if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); + addFrameObject(tobj); + TuioSymbol *tsym = tobj->getTuioSymbol(); + if (tsym == NULL) { + tsym = new TuioSymbol(frameTime,tobj,t_id,u_id,c_id,type,data); + tobj->setTuioSymbol(tsym); + } else { + tsym->update(frameTime); + } + + } else if( strcmp( msg.AddressPattern(), "/tuio2/chg" ) == 0 ) { + if (lateFrame) return; + int32 s_id_raw; + args >> s_id_raw; + unsigned int s_id = (unsigned int)s_id_raw; + + std::list pointList; + while(!args.Eos()) { + float xpos, ypos; + args >> xpos >> ypos; + pointList.push_back(TuioPoint(frameTime, xpos, ypos)); + } + + TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); + if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); + addFrameObject(tobj); + + /*TuioGeometry *tgeo = tobj->getTuioGeometry(); + if (tgeo == NULL) { + tgeo = new TuioGeometry(frameTime, tobj); + tobj->setTuioGeometry(tgeo); + } tgeo->setConvexHull(pointList);*/ + + } else if( strcmp( msg.AddressPattern(), "/tuio2/ocg" ) == 0 ) { + if (lateFrame) return; + int32 s_id_raw; + args >> s_id_raw; + unsigned int s_id = (unsigned int)s_id_raw; + + std::list pointList; + while(!args.Eos()) { + float xpos, ypos; + args >> xpos >> ypos; + pointList.push_back(TuioPoint(frameTime, xpos, ypos)); + } + + TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); + if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); + addFrameObject(tobj); + + /*TuioGeometry *tgeo = tobj->getTuioGeometry(); + if (tgeo == NULL) { + tgeo = new TuioGeometry(frameTime, tobj); + tobj->setTuioGeometry(tgeo); + } tgeo->setOuterContour(pointList);*/ + + } else if( strcmp( msg.AddressPattern(), "/tuio2/icg" ) == 0 ) { + if (lateFrame) return; + int32 s_id_raw; + args >> s_id_raw; + unsigned int s_id = (unsigned int)s_id_raw; + + std::list pointList; + while(!args.Eos()) { + float xpos,ypos; + args >> xpos >> ypos; + pointList.push_back(TuioPoint(frameTime, xpos, ypos)); + } + + TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); + if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); + addFrameObject(tobj); + + /*TuioGeometry *tgeo = tobj->getTuioGeometry(); + if (tgeo == NULL) { + tgeo = new TuioGeometry(frameTime, tobj); + tobj->setTuioGeometry(tgeo); + } tgeo->setOuterContour(pointList);*/ + + } else if( strcmp( msg.AddressPattern(), "/tuio2/alv" ) == 0 ) { + + if (lateFrame) return; + int32 s_id; + aliveObjectList.clear(); + while(!args.Eos()) { + args >> s_id; + aliveObjectList.push_back((unsigned int)s_id); + } + + lockObjectList(); + //find the removed tobjs first + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + if ((*tobj)->getTuioSource()->getSourceID()!=frameSource->getSourceID()) continue; + std::list::iterator iter = find(aliveObjectList.begin(), aliveObjectList.end(), (*tobj)->getSessionID()); + if (iter == aliveObjectList.end()) { + (*tobj)->remove(frameTime); + addFrameObject(*tobj); + } + } + unlockObjectList(); + + for (std::list::iterator iter=frameObjectList.begin(); iter!=frameObjectList.end(); iter++) { + TuioObject *tobj = (*iter); + + switch (tobj->getTuioState()) { + case TUIO_REMOVED: + + for (std::list::iterator listener=listenerList.begin(); listener!=listenerList.end(); listener++) + (*listener)->tuioRemove(tobj); + + lockObjectList(); + for (std::list::iterator delcon=tobjList.begin(); delcon!=tobjList.end(); delcon++) { + if (((*delcon)->getSessionID()==tobj->getSessionID()) && ((*delcon)->getTuioSource()->getSourceID()==frameSource->getSourceID())) { + delete *delcon; + tobjList.erase(delcon); + break; + } + } + unlockObjectList(); + break; + case TUIO_ADDED: + + lockObjectList(); + tobjList.push_back(tobj); + unlockObjectList(); + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioAdd(tobj); + + break; + default: + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioUpdate(tobj); + } + } + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioRefresh(frameTime); + + frameObjectList.clear(); + //unlockFrame(); + } + } catch( Exception& e ){ + std::cerr << "error parsing TUIO2 message: "<< msg.AddressPattern() << " - " << e.what() << std::endl; + //unlockFrame(); + } +} + +bool TuioClient::isConnected() { + return receiver->isConnected(); +} + +void TuioClient::connect(bool lock) { + + receiver->connect(lock); + unlockObjectList(); +} + +void TuioClient::disconnect() { + + receiver->disconnect(); + aliveObjectList.clear(); + + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) + delete (*iter); + tobjList.clear(); +} + +TuioObject* TuioClient::getTuioObject(unsigned int src_id, unsigned int s_id) { + lockObjectList(); + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { + unlockObjectList(); + return (*iter); + } + } + unlockObjectList(); + return NULL; +} + +TuioToken* TuioClient::getTuioToken(unsigned int src_id, unsigned int s_id) { + lockObjectList(); + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { + unlockObjectList(); + return (*iter)->getTuioToken(); + } + } + unlockObjectList(); + return NULL; +} + +TuioPointer* TuioClient::getTuioPointer(unsigned int src_id, unsigned int s_id) { + lockObjectList(); + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { + unlockObjectList(); + return (*iter)->getTuioPointer(); + } + } + unlockObjectList(); + return NULL; +} + +TuioBounds* TuioClient::getTuioBounds(unsigned int src_id, unsigned int s_id) { + lockObjectList(); + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { + unlockObjectList(); + return (*iter)->getTuioBounds(); + } + } + unlockObjectList(); + return NULL; +} + +TuioSymbol* TuioClient::getTuioSymbol(unsigned int src_id, unsigned int s_id) { + lockObjectList(); + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { + unlockObjectList(); + return (*iter)->getTuioSymbol(); + } + } + unlockObjectList(); + return NULL; +} + +std::list TuioClient::getTuioObjectList(unsigned int src_id) { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { + if ((*tobj)->getTuioSource()->getSourceID()==src_id) listBuffer.push_back(*tobj); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioClient::getTuioTokenList(unsigned int src_id) { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { + if ((*tobj)->getTuioSource()->getSourceID()==src_id) { + TuioToken *ttok = (*tobj)->getTuioToken(); + if (ttok!=NULL) listBuffer.push_back(ttok); + } + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioClient::getTuioPointerList(unsigned int src_id) { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { + if ((*tobj)->getTuioSource()->getSourceID()==src_id) { + TuioPointer *tptr = (*tobj)->getTuioPointer(); + if (tptr!=NULL) listBuffer.push_back(tptr); + } + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioClient::getTuioBoundsList(unsigned int src_id) { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { + if ((*tobj)->getTuioSource()->getSourceID()==src_id) { + TuioBounds *tbnd = (*tobj)->getTuioBounds(); + if (tbnd!=NULL) listBuffer.push_back(tbnd); + } + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioClient::getTuioSymbolList(unsigned int src_id) { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { + if ((*tobj)->getTuioSource()->getSourceID()==src_id) { + TuioSymbol *tsym = (*tobj)->getTuioSymbol(); + if (tsym!=NULL) listBuffer.push_back(tsym); + } + } + unlockObjectList(); + return listBuffer; +} + +void TuioClient::addFrameObject(TuioObject *tobj) { + for (std::list::iterator iter=frameObjectList.begin(); iter != frameObjectList.end(); iter++) { + if ((*iter)->getSessionID()==tobj->getSessionID()) return; + } + + frameObjectList.push_back(tobj); +} + +TuioObject* TuioClient::getFrameObject(unsigned int src_id, unsigned int s_id) { + for (std::list::iterator tobj=frameObjectList.begin(); tobj != frameObjectList.end(); tobj++) { + if ((*tobj)->getSessionID()==s_id) return *tobj; + } + + for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { + if (((*tobj)->getSessionID()==s_id) && ((*tobj)->getTuioSource()->getSourceID()==src_id)) return *tobj; + } + + return NULL; +} + +void TuioClient::lockFrame() { +#ifndef WIN32 + pthread_mutex_lock(&frameMutex); +#else + WaitForSingleObject(frameMutex, INFINITE); +#endif +} + +void TuioClient::unlockFrame() { +#ifndef WIN32 + pthread_mutex_unlock(&frameMutex); +#else + ReleaseMutex(frameMutex); +#endif +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioClient.h b/modules/touch/ext/libTUIO2/TUIO2/TuioClient.h new file mode 100644 index 0000000000..65582f5f67 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioClient.h @@ -0,0 +1,241 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOCLIENT_H +#define INCLUDED_TUIOCLIENT_H + +#include "TuioDispatcher.h" +#include "OscReceiver.h" +#include "oscpack/osc/OscReceivedElements.h" + +#include +#include +#include +#include +#include +#include + +namespace TUIO2 { + + class OscReceiver; // Forward declaration + + /** + *

The TuioClient class is the central TUIO protocol decoder component. It provides a simple callback infrastructure using the {@link TuioListener} interface. + * In order to receive and decode TUIO messages an instance of TuioClient needs to be created. The TuioClient instance then generates TUIO events + * which are broadcasted to all registered classes that implement the {@link TuioListener} interface.

+ *

+ * TuioClient *client = new TuioClient();
+ * client->addTuioListener(myTuioListener);
+ * client->connect();
+ *

+ * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioClient : public TuioDispatcher { + + public: + /** + * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the default UDP port 3333 + * + */ + TuioClient(); + + /** + * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the provided UDP port + * + * @param port the UDP port the internal UdpReceiver is listening to + */ + TuioClient(unsigned short port); + + /** + * This constructor creates a TuioClient that uses the provided OscReceiver for the incoming OSC data + * + * @param oscreceiver the OscReceiver implementation for the chosen transport method (UDP, TCP ...) + */ + TuioClient(OscReceiver *oscreceiver); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioClient(); + + /** + * The TuioClient connects and starts receiving TUIO messages from its associated OscReceiver + * + * @param lock running in the background if set to false (default) + */ + void connect(bool lock=false); + + /** + * The TuioClient disconnects and stops receiving TUIO messages from its associated OscReceiver + */ + void disconnect(); + + /** + * Returns true if this TuioClient is currently connected. + * @return true if this TuioClient is currently connected + */ + bool isConnected(); + + /** + * Returns the TuioObject corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioObject + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioObject + * @return an active TuioObject corresponding to the provided Session ID or NULL + */ + using TuioDispatcher::getTuioObject; + TuioObject* getTuioObject(unsigned int src_id, unsigned int s_id); + + /** + * Returns a list of all currently active TuioObject + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a list of TuioObject + */ + using TuioDispatcher::getTuioObjectList; + std::list getTuioObjectList(unsigned int src_id); + + /** + * Returns the TuioToken corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioToken + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioToken + * @return an active TuioToken corresponding to the provided Session ID or NULL + */ + using TuioDispatcher::getTuioToken; + TuioToken* getTuioToken(unsigned int src_id, unsigned int s_id); + + /** + * Returns a list of all currently active TuioTokens + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a list of TuioTokens + */ + using TuioDispatcher::getTuioTokenList; + std::list getTuioTokenList(unsigned int src_id); + + /** + * Returns the TuioPointer corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioPointer + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioPointer + * @return an active TuioPointer corresponding to the provided Session ID or NULL + */ + using TuioDispatcher::getTuioPointer; + TuioPointer* getTuioPointer(unsigned int src_id, unsigned int s_id); + + /** + * Returns a List of all currently active TuioPointers + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List of TuioPointers + */ + using TuioDispatcher::getTuioPointerList; + std::list getTuioPointerList(unsigned int src_id); + + /** + * Returns the TuioBounds corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioBounds + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioBounds + * @return an active TuioBounds corresponding to the provided Session ID or NULL + */ + using TuioDispatcher::getTuioBounds; + TuioBounds* getTuioBounds(unsigned int src_id, unsigned int s_id); + + /** + * Returns a List of all currently active TuioBounds + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List of TuioBounds + */ + using TuioDispatcher::getTuioBoundsList; + std::list getTuioBoundsList(unsigned int src_id); + + /** + * Returns the TuioSymbol corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioSymbol + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioSymbol + * @return an active TuioSymbol corresponding to the provided Session ID or NULL + */ + using TuioDispatcher::getTuioSymbol; + TuioSymbol* getTuioSymbol(unsigned int src_id, unsigned int s_id); + + /** + * Returns a List of all currently active TuioSymbol + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List of TuioSymbol + */ + using TuioDispatcher::getTuioSymbolList; + std::list getTuioSymbolList(unsigned int src_id); + + /** + * Parses the incoming OSC message + * + * @param message the incoming OSC message + */ + void processOSC( const osc::ReceivedMessage& message); + + private: + void initialize(); + + void addFrameObject(TuioObject *con); + TuioObject* getFrameObject(unsigned int src_id,unsigned int s_id); + std::list aliveObjectList; + std::list frameObjectList; + + TuioTime frameTime; + bool lateFrame; + + unsigned int source_count; + std::map sourceList; + TuioSource *frameSource; + + OscReceiver *receiver; + bool local_receiver; + +#ifndef WIN32 + pthread_mutex_t frameMutex; +#else + HANDLE frameMutex; +#endif + + void lockFrame(); + void unlockFrame(); + }; +}; +#endif /* INCLUDED_TUIOCLIENT_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp new file mode 100644 index 0000000000..d27a3dad28 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp @@ -0,0 +1,245 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioComponent.h" +#include "TuioObject.h" +using namespace TUIO2; + +TuioComponent::TuioComponent (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a):TuioPoint(ttime, xp,yp) +,state(TUIO_ADDED) +{ + container = tobj; + angle = a; + x_speed = 0.0f; + y_speed = 0.0f; + motion_speed = 0.0f; + motion_accel = 0.0f; + rotation_speed = 0.0f; + rotation_accel = 0.0f; + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + } + +TuioComponent::TuioComponent (TuioObject *tobj, float xp, float yp, float a):TuioPoint(xp,yp) +,state(TUIO_ADDED) +{ + container = tobj; + angle = a; + x_speed = 0.0f; + y_speed = 0.0f; + motion_speed = 0.0f; + motion_accel = 0.0f; + rotation_speed = 0.0f; + rotation_accel = 0.0f; + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); +} + +TuioComponent::TuioComponent (TuioComponent *tcomp):TuioPoint(tcomp) +,state(TUIO_ADDED) +{ + container = tcomp->getContainingTuioObject(); + angle = tcomp->getAngle(); + x_speed = 0.0f; + y_speed = 0.0f; + motion_speed = 0.0f; + motion_accel = 0.0f; + rotation_speed = 0.0f; + rotation_accel = 0.0f; + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); +} + +TuioObject* TuioComponent::getContainingTuioObject() { + return container; +} + +void TuioComponent::setContainingTuioObject(TuioObject *tobj) { + container = tobj; +} + +void TuioComponent::update (TuioTime ttime, float xp, float yp, float a) { + TuioPoint lastPoint = path.back(); + TuioPoint::update(ttime,xp, yp); + + TuioTime diffTime = currentTime - lastPoint.getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + float dx = xpos - lastPoint.getX(); + float dy = ypos - lastPoint.getY(); + float dist = sqrt(dx*dx+dy*dy); + float last_motion_speed = motion_speed; + + x_speed = dx/dt; + y_speed = dy/dt; + motion_speed = dist/dt; + motion_accel = (motion_speed - last_motion_speed)/dt; + + float last_angle = angle; + float last_rotation_speed = rotation_speed; + angle = a; + + double da = (angle-last_angle)/(2*M_PI); + if (da > 0.75f) da-=1.0f; + else if (da < -0.75f) da+=1.0f; + + rotation_speed = (float)da/dt; + rotation_accel = (rotation_speed - last_rotation_speed)/dt; + + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; + else state = TUIO_STOPPED; + + container->update(ttime); +} + +void TuioComponent::stop(TuioTime ttime) { + update(ttime,xpos,ypos); + container->update(ttime); +} + +void TuioComponent::update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { + TuioPoint::update(ttime,xp, yp); + angle = a; + x_speed = xs; + y_speed = ys; + motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); + rotation_speed = rs; + motion_accel = ma; + rotation_accel = ra; + + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; + else state = TUIO_STOPPED; + + container->update(ttime); + } + +void TuioComponent::update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { + TuioPoint::update(xp,yp); + angle = a; + x_speed = xs; + y_speed = ys; + motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); + rotation_speed = rs; + motion_accel = ma; + rotation_accel = ra; + + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; + else state = TUIO_STOPPED; + + container->update(currentTime); +} + +void TuioComponent::update (TuioComponent *tcomp) { + TuioPoint::update(tcomp); + angle = tcomp->getAngle(); + x_speed = tcomp->getXSpeed(); + y_speed = tcomp->getYSpeed(); + motion_speed = tcomp->getMotionSpeed(); + rotation_speed = tcomp->getRotationSpeed(); + motion_accel = tcomp->getMotionAccel(); + rotation_accel = tcomp->getRotationAccel(); + + TuioPoint p(tcomp->getTuioTime(),xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; + else state = TUIO_STOPPED; + + container->update(tcomp->getTuioTime()); +} + +void TuioComponent::remove(TuioTime ttime) { + currentTime = ttime; + state = TUIO_REMOVED; + container->update(ttime); +} + +unsigned int TuioComponent::getSessionID() const{ + return container->getSessionID(); +} + +float TuioComponent::getAngle() const{ + return angle; +} + +float TuioComponent::getAngleDegrees() const{ + return (float)(angle/M_PI*180); +} + +float TuioComponent::getXSpeed() const{ + return x_speed; +} + +float TuioComponent::getYSpeed() const{ + return y_speed; +} + +TuioPoint TuioComponent::getPosition() const{ + TuioPoint p(xpos,ypos); + return p; +} + +std::list TuioComponent::getPath() const{ + return path; +} + +float TuioComponent::getMotionSpeed() const{ + return motion_speed; +} + +float TuioComponent::getMotionAccel() const{ + return motion_accel; +} + +float TuioComponent::getRotationSpeed() const{ + return rotation_speed; +} + +float TuioComponent::getRotationAccel() const{ + return rotation_accel; +} + +int TuioComponent::getTuioState() const{ + return state; +} + +bool TuioComponent::isMoving() const{ + if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true; + else return false; +} + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h b/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h new file mode 100644 index 0000000000..d7790efe8a --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h @@ -0,0 +1,287 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOCOMPONENT_H +#define INCLUDED_TUIOCOMPONENT_H + +#include "TuioPoint.h" +#include +#include + +#define TUIO_IDLE 0 +#define TUIO_ADDED 1 +#define TUIO_ACCELERATING 2 +#define TUIO_DECELERATING 3 +#define TUIO_ROTATING 4 +#define TUIO_STOPPED 5 +#define TUIO_REMOVED 6 + +#define MAX_PATH_SIZE 128 + +namespace TUIO2 { + + /** + * The abstract TuioComponent class defines common attributes that apply to all subclasses {@link TuioToken}, {@link TuioPointer} and {@link TuioBounds}. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + + class TuioObject; + class LIBDECL TuioComponent: public TuioPoint { + + protected: + /** + * The TuioObject that contains this TUIO component. + */ + TuioObject *container; + /** + * The rotation angle value. + */ + float angle; + /** + * The X-axis velocity value. + */ + float x_speed; + /** + * The Y-axis velocity value. + */ + float y_speed; + /** + * The motion speed value. + */ + float motion_speed; + /** + * The motion acceleration value. + */ + float motion_accel; + /** + * The rotation speed value. + */ + float rotation_speed; + /** + * The rotation acceleration value. + */ + float rotation_accel; + /** + * A List of TuioPoints containing all the previous positions of the TUIO component. + */ + std::list path; + /** + * Reflects the current state of the TuioComponent + */ + int state; + + public: + using TuioPoint::update; + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, X and Y coordinate to the newly created TuioComponent. + * + * @param ttime the TuioTime to assign + * @param tobj the TuioObject to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + TuioComponent (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a); + + /** + * This constructor takes the provided Session ID, X and Y coordinate + * and assigs these values to the newly created TuioComponent. + * + * @param tobj the TuioObject to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + TuioComponent (TuioObject *tobj, float xp, float yp,float a); + + /** + * This constructor takes the atttibutes of the provided TuioComponent + * and assigs these values to the newly created TuioComponent. + * + * @param tcon the TuioComponent to assign + */ + TuioComponent (TuioComponent *tcon); + + /** + * The destructor is doing nothing in particular. + */ + virtual ~TuioComponent(){}; + + /** + * Returns the TuioObject containing this TuioComponent. + * @return the TuioObject containing this TuioComponent + */ + virtual TuioObject* getContainingTuioObject(); + + /** + * Returns the TuioObject containing this TuioComponent. + * @param the TuioObject containing this TuioComponent + */ + virtual void setContainingTuioObject(TuioObject *tobj); + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate to the private TuioComponent attributes. + * The speed and accleration values are calculated accordingly. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + virtual void update (TuioTime ttime, float xp, float yp, float a); + + /** + * This method is used to calculate the speed and acceleration values of + * TuioComponents with unchanged positions. + */ + virtual void stop(TuioTime ttime); + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate, X and Y velocity and acceleration + * to the private TuioComponent attributes. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param rs the rotation velocity to assign + * @param ma the motion acceleration to assign + * @param ra the rotation acceleration to assign + */ + virtual void update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); + + /** + * Assigns the provided X and Y coordinate, X and Y velocity and acceleration + * to the private TuioComponent attributes. The TuioTime time stamp remains unchanged. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param rs the rotation velocity to assign + * @param ma the motion acceleration to assign + * @param ra the rotation acceleration to assign + */ + virtual void update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); + + /** + * Takes the atttibutes of the provided TuioComponent + * and assigs these values to this TuioComponent. + * The TuioTime time stamp of this TuioComponent remains unchanged. + * + * @param tcon the TuioComponent to assign + */ + virtual void update(TuioComponent *tcon); + + /** + * Assigns the REMOVE state to this TuioComponent and sets + * its TuioTime time stamp to the provided TuioTime argument. + * + * @param ttime the TuioTime to assign + */ + virtual void remove(TuioTime ttime); + + /** + * Returns the Session ID of this TuioComponent. + * @return the Session ID of this TuioComponent + */ + virtual unsigned int getSessionID() const; + + /** + * Returns the X velocity of this TuioComponent. + * @return the X velocity of this TuioComponent + */ + virtual float getXSpeed() const; + + /** + * Returns the Y velocity of this TuioComponent. + * @return the Y velocity of this TuioComponent + */ + virtual float getYSpeed() const; + + /** + * Returns the position of this TuioComponent. + * @return the position of this TuioComponent + */ + virtual TuioPoint getPosition() const; + + /** + * Returns the path of this TuioComponent. + * @return the path of this TuioComponent + */ + virtual std::list getPath() const; + + /** + * Returns the motion speed of this TuioComponent. + * @return the motion speed of this TuioComponent + */ + virtual float getMotionSpeed() const; + + /** + * Returns the motion acceleration of this TuioComponent. + * @return the motion acceleration of this TuioComponent + */ + virtual float getMotionAccel() const; + + /** + * Returns the rotation angle of this TuioComponent. + * @return the rotation angle of this TuioComponent + */ + float getAngle() const; + + /** + * Returns the rotation angle in degrees of this TuioComponent. + * @return the rotation angle in degrees of this TuioComponent + */ + float getAngleDegrees() const; + + /** + * Returns the rotation speed of this TuioComponent. + * @return the rotation speed of this TuioComponent + */ + float getRotationSpeed() const; + + /** + * Returns the rotation acceleration of this TuioComponent. + * @return the rotation acceleration of this TuioComponent + */ + float getRotationAccel() const; + + /** + * Returns the TUIO state of this TuioComponent. + * @return the TUIO state of this TuioComponent + */ + virtual int getTuioState() const; + + /** + * Returns true of this TuioComponent is moving. + * @return true of this TuioComponent is moving + */ + virtual bool isMoving() const; + }; +} +#endif // INCLUDED_TUIOCOMPONENT_H \ No newline at end of file diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp new file mode 100644 index 0000000000..d3ff480026 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp @@ -0,0 +1,165 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioDispatcher.h" + +#include +#include +#include +#include + +using namespace TUIO2; + +TuioDispatcher::TuioDispatcher() { +#ifndef WIN32 + pthread_mutex_init(&tobjMutex,NULL); +#else + tobjMutex = CreateMutex(NULL,FALSE,"tobjMutex"); +#endif +} + +TuioDispatcher::~TuioDispatcher() { +#ifndef WIN32 + pthread_mutex_destroy(&tobjMutex); +#else + CloseHandle(tobjMutex); +#endif +} + +void TuioDispatcher::lockObjectList() { +#ifndef WIN32 + pthread_mutex_lock(&tobjMutex); +#else + WaitForSingleObject(tobjMutex, INFINITE); +#endif +} + +void TuioDispatcher::unlockObjectList() { +#ifndef WIN32 + pthread_mutex_unlock(&tobjMutex); +#else + ReleaseMutex(tobjMutex); +#endif +} + +void TuioDispatcher::addTuioListener(TuioListener *listener) { + listenerList.push_back(listener); +} + +void TuioDispatcher::removeTuioListener(TuioListener *listener) { + std::list::iterator result = find(listenerList.begin(),listenerList.end(),listener); + if (result!=listenerList.end()) listenerList.remove(listener); +} + +void TuioDispatcher::removeAllTuioListeners() { + listenerList.clear(); +} + +TuioObject* TuioDispatcher::getTuioObject(unsigned int s_id) { + lockObjectList(); + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + if((*tobj)->getSessionID()==s_id) { + unlockObjectList(); + return (*tobj); + } + } + unlockObjectList(); + return NULL; +} + +TuioToken* TuioDispatcher::getTuioToken(unsigned int s_id) { + TuioObject *tobj = getTuioObject(s_id); + if (tobj==NULL) return NULL; + + return tobj->getTuioToken(); +} + +TuioPointer* TuioDispatcher::getTuioPointer(unsigned int s_id) { + TuioObject *tobj = getTuioObject(s_id); + if (tobj==NULL) return NULL; + + return tobj->getTuioPointer(); +} + +TuioBounds* TuioDispatcher::getTuioBounds(unsigned int s_id) { + TuioObject *tobj = getTuioObject(s_id); + if (tobj==NULL) return NULL; + + return tobj->getTuioBounds(); +} + +TuioSymbol* TuioDispatcher::getTuioSymbol(unsigned int s_id) { + TuioObject *tobj = getTuioObject(s_id); + if (tobj==NULL) return NULL; + + return tobj->getTuioSymbol(); +} + +std::list TuioDispatcher::getTuioObjectList() { + std::list listBuffer; + lockObjectList(); + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + listBuffer.push_back(*tobj); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioDispatcher::getTuioTokenList() { + std::list listBuffer; + lockObjectList(); + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + TuioToken *ttok = (*tobj)->getTuioToken(); + if (ttok!=NULL) listBuffer.push_back(ttok); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioDispatcher::getTuioPointerList() { + std::list listBuffer; + lockObjectList(); + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + TuioPointer *tptr = (*tobj)->getTuioPointer(); + if (tptr!=NULL) listBuffer.push_back(tptr); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioDispatcher::getTuioBoundsList() { + std::list listBuffer; + lockObjectList(); + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + TuioBounds *tbnd = (*tobj)->getTuioBounds(); + if (tbnd!=NULL) listBuffer.push_back(tbnd); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioDispatcher::getTuioSymbolList() { + std::list listBuffer; + lockObjectList(); + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + TuioSymbol *tsym = (*tobj)->getTuioSymbol(); + if (tsym!=NULL) listBuffer.push_back(tsym); + } + unlockObjectList(); + return listBuffer; +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h b/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h new file mode 100644 index 0000000000..966975fea3 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h @@ -0,0 +1,169 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIODISPATCHER_H +#define INCLUDED_TUIODISPATCHER_H + +#include "TuioListener.h" + +#ifndef WIN32 +#include +#else +#include +#endif + +namespace TUIO2 { + + /** + *

The TuioDispatcher generates TUIO events which are broadcasted to all + * registered classes that implement the {@link TuioListener} interface.

+ * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioDispatcher { + + public: + /** + * This constructor creates a TuioDispatcher + * + */ + TuioDispatcher(); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioDispatcher(); + + /** + * Adds the provided TuioListener to the list of registered TUIO event listeners + * + * @param listener the TuioListener to add + */ + void addTuioListener(TuioListener *listener); + + /** + * Removes the provided TuioListener from the list of registered TUIO event listeners + * + * @param listener the TuioListener to remove + */ + void removeTuioListener(TuioListener *listener); + + /** + * Removes all TuioListener from the list of registered TUIO event listeners + */ + void removeAllTuioListeners(); + + /** + * Returns a List of all currently active TuioObject + * + * @return a List of all currently active TuioObject + */ + std::list getTuioObjectList(); + + /** + * Returns a List of all currently active TuioTokens + * + * @return a List of all currently active TuioTokens + */ + std::list getTuioTokenList(); + + /** + * Returns a List of all currently active TuioPointers + * + * @return a List of all currently active TuioPointers + */ + std::list getTuioPointerList(); + + /** + * Returns a List of all currently active TuioBounds + * + * @return a List of all currently active TuioBounds + */ + std::list getTuioBoundsList(); + + /** + * Returns a List of all currently active TuioSymbols + * + * @return a List of all currently active TuioSymbols + */ + std::list getTuioSymbolList(); + + /** + * Returns the TuioObject corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioObject + * + * @return an active TuioObject corresponding to the provided Session ID or NULL + */ + TuioObject* getTuioObject(unsigned int s_id); + + /** + * Returns the TuioToken corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioToken + * + * @return an active TuioToken corresponding to the provided Session ID or NULL + */ + TuioToken* getTuioToken(unsigned int s_id); + + /** + * Returns the TuioPointer corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioPointer + * + * @return an active TuioPointer corresponding to the provided Session ID or NULL + */ + TuioPointer* getTuioPointer(unsigned int s_id); + + /** + * Returns the TuioBounds corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioBounds + * + * @return an active TuioBounds corresponding to the provided Session ID or NULL + */ + TuioBounds* getTuioBounds(unsigned int s_id); + + /** + * Returns the TuioSymbol corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioSymbol + * + * @return an active TuioSymbol corresponding to the provided Session ID or NULL + */ + TuioSymbol* getTuioSymbol(unsigned int s_id); + + /** + * Locks the TuioObject list in order to avoid updates during access + */ + void lockObjectList(); + + /** + * Releases the lock of the TuioObject list + */ + void unlockObjectList(); + + protected: + std::list listenerList; + std::list tobjList; + +#ifndef WIN32 + pthread_mutex_t tobjMutex; +#else + HANDLE tobjMutex; +#endif + + }; +} +#endif /* INCLUDED_TUIODISPATCHER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioListener.h b/modules/touch/ext/libTUIO2/TUIO2/TuioListener.h new file mode 100644 index 0000000000..160d756f33 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioListener.h @@ -0,0 +1,80 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOLISTENER_H +#define INCLUDED_TUIOLISTENER_H + +#include "TuioObject.h" + +namespace TUIO2 { + + /** + *

The TuioListener interface provides a simple callback infrastructure which is used by the {@link TuioClient} class + * to dispatch TUIO events to all registered instances of classes that implement the TuioListener interface defined here.

+ *

Any class that implements the TuioListener interface is required to implement all of the callback methods defined here. + * The {@link TuioClient} makes use of these interface methods in order to dispatch TUIO events to all registered TuioListener implementations.

+ *

+ * public class MyTuioListener implements TuioListener
+ * ...

+ * MyTuioListener listener = new MyTuioListener();
+ * TuioClient client = new TuioClient();
+ * client.addTuioListener(listener);
+ * client.start();
+ *

+ * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioListener { + + public: + /** + * The destructor is doing nothing in particular. + */ + virtual ~TuioListener(){}; + + /** + * This callback method is invoked by the TuioClient when a new TUIO Component is added to the session. + * + * @param tobj the TuioObject reference that encapsulates all related TUIO Components + */ + virtual void tuioAdd(TuioObject *tobj)=0; + + /** + * This callback method is invoked by the TuioClient when an existing TUIO Component is updated during the session. + * + * @param tobj the TuioObject reference that encapsulates all related TUIO Components + */ + virtual void tuioUpdate(TuioObject *tobj)=0; + + /** + * This callback method is invoked by the TuioClient when a TUIO Component is removed from the session. + * + * @param tobj the TuioObject reference that encapsulates all related TUIO Components + */ + virtual void tuioRemove(TuioObject *tobj)=0; + + /** + * This callback method is invoked by the TuioClient to mark the end of a received TUIO message bundle. + * + * @param ftime the TuioTime associated to the current TUIO message bundle + */ + virtual void tuioRefresh(TuioTime ftime)=0; + }; +} +#endif /* INCLUDED_TUIOLISTENER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp new file mode 100644 index 0000000000..070c8f39ba --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp @@ -0,0 +1,575 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioManager.h" +using namespace TUIO2; + +TuioManager::TuioManager() + : currentFrameTime(TuioTime::getSystemTime()) + , currentFrame(-1) + , pointerCount(0) + , maxPointerID(-1) + , sessionID(-1) + , tobjUpdate(false) + , verbose(false) + , invert_x(false) + , invert_y(false) + , invert_a(false) +{ + +} + +TuioManager::~TuioManager() { +} + +TuioObject* TuioManager::createTuioObject() { + sessionID++; + TuioObject *tobj = new TuioObject(sessionID); + tobjList.push_back(tobj); + return tobj; +} + +void TuioManager::addExternalTuioObject(TuioObject *tobj) { + if (tobj==NULL) return; + tobjList.push_back(tobj); + + TuioPointer *tptr = tobj->getTuioPointer(); + if (tptr!=NULL) pointerCount++; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioAdd(tobj); + + if (verbose) std::cout << "add " << tobj->getSessionID() << std::endl; + tobjUpdate = true; +} + +void TuioManager::updateExternalTuioObject(TuioObject *tobj) { + if (tobj==NULL) return; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioUpdate(tobj); + + if (verbose) std::cout << "set " << tobj->getSessionID() << std::endl; + tobjUpdate = true; +} + +void TuioManager::removeExternalTuioObject(TuioObject *tobj) { + if (tobj==NULL) return; + tobjList.remove(tobj); + + TuioPointer *tptr = tobj->getTuioPointer(); + if (tptr!=NULL) pointerCount--; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioRemove(tobj); + + if (verbose) std::cout << "del " << tobj->getSessionID() << std::endl; + tobjUpdate = true; +} + +void TuioManager::removeTuioObject(unsigned int s_id) { + + TuioObject *tobj = NULL; + for(std::list::iterator iter = tobjList.begin();iter!= tobjList.end(); iter++) { + if((*iter)->getSessionID()==s_id) { + tobj = *iter; + break; + } + } + if (tobj==NULL) return; + else removeTuioObject(tobj); +} + +void TuioManager::removeTuioObject(TuioObject *tobj) { + + if (tobj== NULL) return; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioRemove(tobj); + + if (tobj->containsTuioToken()) { + if (verbose) std::cout << "del tok " << tobj->getSessionID() << std::endl; + tobj->deleteTuioToken(); + } + + if (tobj->containsTuioPointer()) { + if (verbose) std::cout << "del ptr " << tobj->getSessionID() << std::endl; + tobj->deleteTuioPointer(); + } + + if (tobj->containsTuioBounds()) { + if (verbose) std::cout << "del bnd " << tobj->getSessionID() << std::endl; + tobj->deleteTuioBounds(); + } + + if (tobj->containsTuioSymbol()) { + if (verbose) std::cout << "del sym " << tobj->getSessionID() << std::endl; + tobj->deleteTuioSymbol(); + } + + tobjList.remove(tobj); + tobjUpdate = true; + delete tobj; +} + +TuioObject* TuioManager::createTuioToken(unsigned int sym, float x, float y, float a) { + return addTuioToken(NULL, sym, 0, 0, x, y, a); +} + +TuioObject* TuioManager::createTuioToken(unsigned int sym, unsigned short t_id, unsigned short u_id, float x, float y, float a) { + return addTuioToken(NULL, sym, t_id, u_id, x, y, a); +} + +TuioObject* TuioManager::addTuioToken(TuioObject *tobj, unsigned int sym, float x, float y, float a) { + return addTuioToken(tobj, sym, 0, 0, x, y, a); +} + +TuioObject* TuioManager::addTuioToken(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, float x, float y, float a) { + + TuioToken *ttok = new TuioToken(currentFrameTime, tobj, t_id, u_id, sym, x, y, a); + return addTuioToken(ttok); +} + +TuioObject* TuioManager::addTuioToken(TuioToken *ttok) { + if (ttok==NULL) return NULL; + + TuioObject *tobj = ttok->getContainingTuioObject(); + if (tobj==NULL) tobj = createTuioObject(); + tobj->setTuioToken(ttok); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { + (*listener)->tuioAdd(tobj); + } + + if (verbose) std::cout << "add tok " << tobj->getSessionID() << std::endl; + tobjUpdate = true; + + return tobj; +} + +void TuioManager::updateTuioToken(TuioToken *ttok, float x, float y, float a) { + if (ttok==NULL) return; + if (ttok->getTuioTime()==currentFrameTime) return; + + ttok->update(currentFrameTime,x,y,a); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioUpdate(ttok->getContainingTuioObject()); + + if (verbose)std::cout << "set tok " << ttok->getSessionID() << std::endl; + tobjUpdate = true; +} + +void TuioManager::removeTuioToken(TuioToken *ttok) { + if (ttok==NULL) return; + + TuioObject *tobj = ttok->getContainingTuioObject(); + if (tobj==NULL) { + delete ttok; + return; + } else removeTuioObject(tobj); +} + +TuioObject* TuioManager::createTuioPointer(float x, float y, float a, float s, float r, float p) { + return addTuioPointer(NULL, 0, 0, x, y, a, s, r, p); +} + +TuioObject* TuioManager::createTuioPointer(unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { + return addTuioPointer(NULL, t_id, u_id, x, y, a, s, r, p); +} + +TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, float x, float y, float a, float s, float r, float p) { + return addTuioPointer(tobj, 0, 0, x, y, a, s, r, p); +} + +TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { + + int pointerID = pointerCount; + if ((pointerCount<=maxPointerID) && (freePointerList.size()>0)) { + std::list::iterator closestPointer = freePointerList.begin(); + + for(std::list::iterator iter = freePointerList.begin();iter!= freePointerList.end(); iter++) { + if((*iter)->getDistance(x,y)<(*closestPointer)->getDistance(x,y)) closestPointer = iter; + } + + TuioPointer *freePointer = (*closestPointer); + pointerID = (*closestPointer)->getPointerID(); + freePointerList.erase(closestPointer); + delete freePointer; + } else maxPointerID = pointerID; + + TuioPointer *tptr = new TuioPointer(currentFrameTime, tobj, t_id, u_id, pointerID, x, y, a, s, r, p); + return addTuioPointer(tptr); +} + +TuioObject* TuioManager::createTuioPointer(unsigned int p_id, float x, float y, float a, float s, float r, float p) { + + return addTuioPointer(NULL, p_id, 0, 0, x, y, a, s, r, p); +} + +TuioObject* TuioManager::createTuioPointer(unsigned int p_id, unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { + + return addTuioPointer(NULL, p_id, t_id, u_id, x, y, a, s, r, p); +} + +TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, unsigned int p_id, float x, float y, float a, float s, float r, float p) { + + return addTuioPointer(tobj, p_id, 0, 0, x, y, a, s, r, p); +} + +TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, unsigned int p_id, unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { + + TuioPointer *tptr = new TuioPointer(currentFrameTime, tobj, t_id, u_id, p_id, x, y, a, s, r, p); + return addTuioPointer(tptr); +} + +TuioObject* TuioManager::addTuioPointer(TuioPointer *tptr) { + if (tptr==NULL) return NULL; + + TuioObject *tobj = tptr->getContainingTuioObject(); + + if (tobj==NULL) tobj = createTuioObject(); + tobj->setTuioPointer(tptr); + pointerCount++; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { + (*listener)->tuioAdd(tobj); + } + + if (verbose) std::cout << "add ptr " << tobj->getSessionID() << std::endl; + tobjUpdate = true; + + return tobj; +} + +void TuioManager::updateTuioPointer(TuioPointer *tptr, float x, float y, float a, float s, float r, float p) { + if (tptr==NULL) return; + if (tptr->getTuioTime()==currentFrameTime) return; + + TuioObject *tobj = tptr->getContainingTuioObject(); + if (tobj==NULL) return; + + tptr->update(currentFrameTime,x,y,a,s,r,p); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioUpdate(tobj); + + if (verbose)std::cout << "set ptr " << tobj->getSessionID() << std::endl; + tobjUpdate = true; +} + +void TuioManager::removeTuioPointer(TuioPointer *tptr) { + if (tptr==NULL) return; + pointerCount--; + + TuioObject *tobj = tptr->getContainingTuioObject(); + + if (tptr->getPointerID()==maxPointerID) { + maxPointerID = -1; + + if (pointerCount>0) { + + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + if ((*iter)->containsTuioPointer()) { + int pointerID = (*iter)->getTuioPointer()->getPointerID(); + if (pointerID>maxPointerID) maxPointerID=pointerID; + } + } + + freePointerBuffer.clear(); + for (std::list::iterator flist=freePointerList.begin(); flist != freePointerList.end(); flist++) { + TuioPointer *freePointer = (*flist); + if (freePointer->getPointerID()<=maxPointerID) freePointerBuffer.push_back(new TuioPointer(freePointer)); + } + + freePointerList = freePointerBuffer; + + } else { + for (std::list::iterator flist=freePointerList.begin(); flist != freePointerList.end(); flist++) { + TuioPointer *freePointer = (*flist); + delete freePointer; + } + freePointerList.clear(); + } + } else if (tptr->getPointerID()getContainingTuioObject(); + + if (tobj==NULL) tobj = createTuioObject(); + tobj->setTuioBounds(tbnd); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { + (*listener)->tuioAdd(tobj); + } + + if (verbose) std::cout << "add bnd " << tobj->getSessionID() << std::endl; + tobjUpdate = true; + + return tobj; +} + +void TuioManager::updateTuioBounds(TuioBounds *tbnd, float x, float y, float a, float w, float h, float f) { + if (tbnd==NULL) return; + if (tbnd->getTuioTime()==currentFrameTime) return; + + tbnd->update(currentFrameTime,x,y,a,w,h,f); + TuioObject *tobj = tbnd->getContainingTuioObject(); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioUpdate(tobj); + + if (verbose)std::cout << "set bnd " << tobj->getSessionID() << std::endl; + tobjUpdate = true; +} + +void TuioManager::removeTuioBounds(TuioBounds *tbnd) { + if (tbnd==NULL) return; + + TuioObject *tobj = tbnd->getContainingTuioObject(); + if (tobj==NULL) { + delete tbnd; + return; + } else removeTuioObject(tobj); +} + +TuioObject* TuioManager::createTuioSymbol(unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data) { + + return addTuioSymbol(NULL, t_id, u_id, sym, type, data); +} + +TuioObject* TuioManager::addTuioSymbol(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data) { + + TuioSymbol *tsym = new TuioSymbol(currentFrameTime, tobj, t_id, u_id, sym, type, data); + return addTuioSymbol(tsym); +} + +TuioObject* TuioManager::addTuioSymbol(TuioSymbol *tsym) { + if (tsym==NULL) return NULL; + + TuioObject *tobj = tsym->getContainingTuioObject(); + if (tobj==NULL) tobj = createTuioObject(); + tobj->setTuioSymbol(tsym); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { + if (tobjUpdate)(*listener)->tuioUpdate(tobj); + else(*listener)->tuioAdd(tobj); + } + + if (verbose) std::cout << "add sym " << tobj->getSessionID() << std::endl; + tobjUpdate = true; + + return tobj; +} + +void TuioManager::removeTuioSymbol(TuioSymbol *tsym) { + if (tsym==NULL) return; + + TuioObject *tobj = tsym->getContainingTuioObject(); + if (tobj==NULL) { + delete tsym; + return; + } else removeTuioObject(tobj); +} + +int TuioManager::getSessionID() { + sessionID++; + if (sessionID==UINT_MAX) sessionID = 0; + return sessionID; +} + +int TuioManager::getFrameID() { + return currentFrame; +} + +TuioTime TuioManager::getFrameTime() { + return currentFrameTime; +} + +void TuioManager::initTuioFrame(TuioTime ttime) { + frameTimeTag = TuioTime::getSystemTimeTag(); + currentFrameTime = TuioTime(ttime); + currentFrame++; + if (currentFrame==UINT_MAX) currentFrame = 1; +} + +void TuioManager::commitTuioFrame() { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->tuioRefresh(currentFrameTime); + + if (verbose) std::cout << "refresh " << currentFrame << " " << currentFrameTime.getTotalMilliseconds() << std::endl; +} + +TuioToken* TuioManager::getClosestTuioToken(float xp, float yp) { + + TuioToken *closestToken = NULL; + float closestDistance = 1.0f; + + for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + TuioToken *ttok = (*iter)->getTuioToken(); + if (ttok==NULL) continue; + float distance = ttok->getDistance(xp,yp); + if(distance::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { + TuioPointer *tptr = (*iter)->getTuioPointer(); + if (tptr==NULL) continue; + float distance = tptr->getDistance(xp,yp); + if(distance::iterator iter=tobjList.begin(); iter!=tobjList.end(); iter++) { + TuioBounds *tbnd = (*iter)->getTuioBounds(); + if (tbnd==NULL) continue; + float distance = tbnd->getDistance(xp,yp); + if(distance TuioManager::getUntouchedObjects() { + + std::list untouched; + for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { + + bool touched = false; + if ((*tobj)->containsTuioToken()) { + if ((*tobj)->getTuioToken()->getTuioTime()==currentFrameTime) touched=true; + } + + if ((*tobj)->containsTuioPointer()) { + if ((*tobj)->getTuioPointer()->getTuioTime()==currentFrameTime) touched=true; + } + + if ((*tobj)->containsTuioBounds()) { + if ((*tobj)->getTuioToken()->getTuioTime()==currentFrameTime) touched=true; + } + + if ((*tobj)->containsTuioSymbol()) { + if ((*tobj)->getTuioSymbol()->getTuioTime()==currentFrameTime) touched=true; + } + + if (!touched) untouched.push_back(*tobj); + + } + return untouched; +} + +void TuioManager::stopUntouchedMovingObjects() { + + for (std::list::iterator tobj = tobjList.begin(); tobj!=tobjList.end(); tobj++) { + + if ((*tobj)->containsTuioToken()) { + TuioToken *ttok = (*tobj)->getTuioToken(); + if ((ttok->getTuioTime()!=currentFrameTime) && (ttok->isMoving())) { + ttok->stop(currentFrameTime); + if (verbose) std::cout << "set tok " << ttok->getSessionID() << std::endl; + tobjUpdate = true; + } + } + + if ((*tobj)->containsTuioPointer()) { + TuioPointer *tptr = (*tobj)->getTuioPointer(); + if ((tptr->getTuioTime()!=currentFrameTime) && (tptr->isMoving())) { + tptr->stop(currentFrameTime); + if (verbose) std::cout << "set ptr " << tptr->getSessionID() << std::endl; + tobjUpdate = true; + } + } + + if ((*tobj)->containsTuioBounds()) { + TuioBounds *tbnd = (*tobj)->getTuioBounds(); + if ((tbnd->getTuioTime()!=currentFrameTime) && (tbnd->isMoving())) { + tbnd->stop(currentFrameTime); + if (verbose) std::cout << "set bnd " << tbnd->getSessionID() << std::endl; + tobjUpdate = true; + } + } + + } +} + +void TuioManager::removeUntouchedStoppedObjects() { + std::list::iterator iter = tobjList.begin(); + while (iter!=tobjList.end()) { + TuioObject *tobj = (*iter); + if ((tobj->getTuioTime()!=currentFrameTime) && (!tobj->isMoving())) { + removeTuioObject(tobj); + iter = tobjList.begin(); + } else iter++; + } +} + +void TuioManager::resetTuioObjectList() { + + pointerCount=0; + std::list::iterator tobj = tobjList.begin(); + while (tobj!=tobjList.end()) { + removeTuioObject((*tobj)); + tobj = tobjList.begin(); + } +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioManager.h b/modules/touch/ext/libTUIO2/TUIO2/TuioManager.h new file mode 100644 index 0000000000..fac3d55327 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioManager.h @@ -0,0 +1,601 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOMANAGER_H +#define INCLUDED_TUIOMANAGER_H + +#include "TuioDispatcher.h" + +#include +#include +#include + +namespace TUIO2 { + /** + *

The TuioManager class is the central TUIO session management component.

+ *

During runtime the each frame is marked with the initFrame and commitFrame methods, + * while the currently present TuioTokens are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

+ *

+ * TuioManager *manager = new TuioManager();
+ * ...
+ * server->initTuioFrame(TuioTime::getSessionTime());
+ * TuioToken *ttok = server->addTuioToken(xpos,ypos, angle);
+ * TuioPointer *tptr = server->addTuioToken(xpos,ypos);
+ * TuioBounds *tbnd = server->addTuioBounds(xpos,ypos,width,height,angle);
+ * server->commitFrame();
+ * ...
+ * server->initFrame(TuioTime::getSessionTime());
+ * server->updateTuioToken(ttok, xpos,ypos, angle);
+ * server->updateTuioPointer(tptr, xpos,ypos);
+ * server->updateTuioBounds(tbnd, xpos,ypos,width,height,angle);
+ * server->commitFrame();
+ * ...
+ * server->initFrame(TuioTime::getSessionTime());
+ * server->removeTuioToken(ttok);
+ * server->removeTuioPointer(tptr);
+ * server->removeTuioBounds(tbnd);
+ * server->commitFrame();
+ *

+ * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioManager : public TuioDispatcher { + + public: + + /** + * The default constructor creates a TuioManager + */ + TuioManager(); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioManager(); + + /** + * Adds an externally managed TuioObject to the TuioServer's internal list of active TuioObjects + * + * @param tobj the TuioObject to add + */ + void addExternalTuioObject(TuioObject *tobj); + + /** + * Updates an externally managed TuioObject + * + * @param tobj the TuioObject to update + */ + void updateExternalTuioObject(TuioObject *tobj); + + /** + * Removes an externally managed TuioObject from the TuioServer's internal list of TuioObjects + * The referenced TuioObject is not deleted + * + * @param tobj the TuioObject to remove + */ + void removeExternalTuioObject(TuioObject *tobj); + + /** + * Creates an internally managed TuioObject with a new Session ID + * and adds it to the TuioServer's internal list of TuioObjects + * + * @return the newly created but empty TuioObject + */ + TuioObject* createTuioObject(); + + /** + * Removes an internally managed TuioObject from the TuioServer's internal list of TuioObjects + * The provided TuioObject (and all its encapsulated TUIO Components) are deleted + * + * @param s_id the Session ID of the internal TuioObject to remove + */ + void removeTuioObject(unsigned int s_id); + + /** + * Removes an internally managed TuioObject from the TuioServer's internal list of TuioObjects + * The provided TuioObject (and all its encapsulated TUIO Components) are deleted + * + * @param tobj the internal TuioObject to remove + */ + void removeTuioObject(TuioObject *tobj); + + /** + * Creates a new TuioToken based on the given arguments. + * A new TuioObject containing that TuioToken is added + * to the TuioServer's internal list of TuioObjects + * and the TuioToken reference is returned to the caller. + * + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @return reference to the created TuioToken + */ + TuioObject* createTuioToken(unsigned int sym, float xp, float yp, float a); + + /** + * Creates a new TuioToken based on the given arguments. + * A new TuioObject containing that TuioToken is added + * to the TuioServer's internal list of TuioObjects + * and the TuioToken reference is returned to the caller. + * + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @return a reference to the TuioObject of the TuioToken + */ + TuioObject* createTuioToken(unsigned int sym, unsigned short t_id, unsigned short u_id, float xp, float yp, float a); + + /** + * Creates a new TuioToken based on the given arguments. + * and adds it to an existing TuioObject with the Session ID + * from the TuioServer's internal list of TuioObjects + * and the TuioToken reference is returned to the caller. + * + * @param tobj the existing TuioObject + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @return a reference to the TuioObject of the TuioToken + */ + TuioObject* addTuioToken(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, float xp, float yp, float a); + + /** + * Creates a new TuioToken based on the given arguments. + * and adds it to an existing TuioObject with the Session ID + * from the TuioServer's internal list of TuioObjects + * and the TuioToken reference is returned to the caller. + * + * @param tobj the existing TuioObject + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @return a reference to the TuioObject of the TuioToken + */ + TuioObject* addTuioToken(TuioObject *tobj, unsigned int sym, float xp, float yp, float a); + + /** + * Adds the provided TuioToken to an existing TuioObject + * from the TuioServer's internal list of TuioObjects + * or creates the according TuioObject if not found. + * + * @param ttok the existing TuioToken to add + * @return a reference to the TuioObject of the TuioToken + */ + TuioObject* addTuioToken(TuioToken *ttok); + + /** + * Updates the referenced TuioToken based on the given arguments. + * + * @param ttok the TuioToken to update + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + void updateTuioToken(TuioToken *ttok, float xp, float yp, float a); + + /** + * Removes the provided TuioToken from an existing TuioObject + * and also deletes the TuioObject with all other components + * + * @param ttok the TuioToken to remove + */ + void removeTuioToken(TuioToken *ttok); + + /** + * Creates a new TuioPointer based on the given arguments. + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference is returned to the caller. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return a reference to the TuioObject of the TuioPointer + */ + TuioObject* createTuioPointer(float xp, float yp, float a, float s, float r, float p); + + /** + * Creates a new TuioPointer based on the given arguments. + * and adds it to an existing TuioObject with the Session ID + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference of the TuioObject is returned to the caller. + * + * @param tobj the existing TuioObject + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return a reference to the TuioObject of the TuioPointer + */ + TuioObject* addTuioPointer(TuioObject *tobj, float xp, float yp, float a, float s, float r, float p); + + /** + * Creates a new TuioPointer based on the given arguments. + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference is returned to the caller. + * + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return a reference to the TuioObject of the TuioPointer + */ + TuioObject* createTuioPointer(unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); + + /** + * Creates a new TuioPointer based on the given arguments. + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference is returned to the caller. + * + * @param tobj the existing TuioObject + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return a reference to the TuioObject of the TuioPointer + */ + TuioObject* addTuioPointer(TuioObject *tobj, unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); + + /** + * Creates a new TuioPointer based on the given arguments. + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference is returned to the caller. + * + * @param p_id the Pointer ID to assign + * @param xp the X coordinate to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return reference to the created TuioPointer + */ + TuioObject* createTuioPointer(unsigned int p_id, float xp, float yp, float a, float s, float r, float p); + + /** + * Creates a new TuioPointer based on the given arguments. + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference is returned to the caller. + * + * @param tobj the existing TuioObject + * @param p_id the Pointer ID to assign + * @param xp the X coordinate to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return reference to the created TuioPointer + */ + TuioObject* addTuioPointer(TuioObject *tobj, unsigned int p_id, float xp, float yp, float a, float s, float r, float p); + + /** + * Creates a new TuioPointer based on the given arguments. + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference is returned to the caller. + * + * @param p_id the Pointer ID to assign + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param xp the X coordinate to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return a reference to the TuioObject of the TuioPointer + */ + TuioObject* createTuioPointer(unsigned int p_id, unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); + + /** + * Creates a new TuioPointer based on the given arguments. + * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers + * and a reference is returned to the caller. + * + * @param tobj the existing TuioObject + * @param p_id the Pointer ID to assign + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param xp the X coordinate to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @return a reference to the TuioObject of the TuioPointer + */ + TuioObject* addTuioPointer(TuioObject *tobj, unsigned int p_id, unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); + + /** + * Adds the provided TuioPointer to an existing TuioObject + * from the TuioServer's internal list of TuioObjects + * or creates the according TuioObject if not found. + * + * @param tptr the existing TuioPointer to add + * @return a reference to the TuioObject of the TuioPointer + */ + TuioObject* addTuioPointer(TuioPointer *tptr); + + /** + * Updates the referenced TuioPointer based on the given arguments. + * + * @param tptr the TuioPointer to update + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the rotation angle to assign + * @param s the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + */ + void updateTuioPointer(TuioPointer *tptr, float xp, float yp, float a, float s, float r, float p); + + /** + * Removes the provided TuioPointer from an existing TuioObject + * and also deletes the TuioObject with all other components + * + * @param tptr the TuioPointer to remove + */ + void removeTuioPointer(TuioPointer *tptr); + + /** + * Creates a new TuioBounds based on the given arguments. + * The new TuioBounds is added to the TuioServer's internal list of active TuioBounds + * and a reference is returned to the caller. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param angle the angle to assign + * @param width the width to assign + * @param height the height to assign + * @param area the area to assign + * @return a reference to the TuioObject of the TuioBounds + */ + TuioObject* createTuioBounds(float xp, float yp, float angle, float width, float height, float area); + + /** + * Creates a new TuioBounds based on the given arguments. + * The new TuioBounds is added to the TuioServer's internal list of active TuioBounds + * and a reference is returned to the caller. + * + * @param tobj the existing TuioObject + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param angle the angle to assign + * @param width the width to assign + * @param height the height to assign + * @param area the area to assign + * @return a reference to the TuioObject of the TuioBounds + */ + TuioObject* addTuioBounds(TuioObject *tobj, float xp, float yp, float angle, float width, float height, float area); + + /** + * Adds the provided TuioBounds to an existing TuioObject + * from the TuioServer's internal list of TuioObjects + * or creates the according TuioObject if not found. + * + * @param tbnd the TuioBounds to add + * @return a reference to the TuioObject of the TuioBounds + */ + TuioObject* addTuioBounds(TuioBounds *tbnd); + + /** + * Updates the referenced TuioBounds based on the given arguments. + * + * @param tbnd the TuioToken to update + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param angle the angle to assign + * @param width the width to assign + * @param height the height to assign + * @param area the area to assign + */ + void updateTuioBounds(TuioBounds *tbnd, float xp, float yp, float angle, float width, float height, float area); + + /** + * Removes the referenced TuioBounds from the TuioServer's internal list of TuioObjects + * and also deletes its TuioObject (and all its encapsulated TUIO Components) + * + * @param tbnd the TuioBounds to remove + */ + void removeTuioBounds(TuioBounds *tbnd); + + /** + * Creates a new TuioSymbol based on the given arguments. + * The new TuioSymbol is added to the TuioServer's internal list of TuioObjects + * and a reference is returned to the caller. + * + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param sym the Symbol ID to assign + * @param type the type descriptor to assign + * @param data the synbol data to assign + * @return a reference to the TuioObject of the TuioSymbol + */ + TuioObject* createTuioSymbol(unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data); + + /** + * Creates a new TuioSymbol based on the given arguments. + * The new TuioSymbol is added to the TuioServer's internal list of TuioObjects + * and a reference is returned to the caller. + * + * @param tobj the existing TuioObject + * @param t_id the Type ID to assign + * @param u_id the User ID to assign + * @param sym the Symbol ID to assign + * @param type the type descriptor to assign + * @param data the synbol data to assign + * @return a reference to the TuioObject of the TuioSymbol + */ + TuioObject* addTuioSymbol(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data); + + /** + * Adds the provided TuioSymbol to an existing TuioObject + * from the TuioServer's internal list of TuioObjects + * or creates the according TuioObject if not found. + * + * @param tsym the TuioSymbol to add + * @return a reference to the TuioObject of the TuioSymbol + */ + TuioObject* addTuioSymbol(TuioSymbol *tsym); + + /** + * Removes the referenced TuioSymbol from the TuioServer's internal list of TuioObjects + * and also deletes its TuioObject (and all its encapsulated TUIO Components) + * + * @param tsym the TuioSymbol to remove + */ + void removeTuioSymbol(TuioSymbol *tsym); + + /** + * Initializes a new frame with the given TuioTime + * + * @param ttime the frame time + */ + void initTuioFrame(TuioTime ttime); + + /** + * Commits the current frame. + * Generates and sends TUIO messages of all currently active and updated TuioTokens and TuioPointers. + */ + void commitTuioFrame(); + + /** + * Returns the next available Session ID for external use. + * @return the next available Session ID for external use + */ + int getSessionID(); + + /** + * Returns the current frame ID for external use. + * @return the current frame ID for external use + */ + int getFrameID(); + + /** + * Returns the current frame time for external use. + * @return the current frame time for external use + */ + TuioTime getFrameTime(); + + /** + * Returns a List of all currently inactive TuioObjects + * + * @return a List of all currently inactive TuioObjects + */ + std::list getUntouchedObjects(); + + /** + * Calculates speed and acceleration values for all currently inactive TuioObjects + */ + void stopUntouchedMovingObjects(); + + /** + * Removes all currently inactive TuioObjects from the TuioServer's internal list + */ + void removeUntouchedStoppedObjects(); + + /** + * Returns the TuioToken closest to the provided coordinates + * or NULL if there isn't any active TuioToken + * + * @return the closest TuioToken to the provided coordinates or NULL + */ + TuioToken* getClosestTuioToken(float xp, float yp); + + /** + * Returns the TuioPointer closest to the provided coordinates + * or NULL if there isn't any active TuioPointer + * + * @return the closest TuioPointer corresponding to the provided coordinates or NULL + */ + TuioPointer* getClosestTuioPointer(float xp, float yp); + + /** + * Returns the TuioBounds closest to the provided coordinates + * or NULL if there isn't any active TuioBounds + * + * @return the closest TuioBounds corresponding to the provided coordinates or NULL + */ + TuioBounds* getClosestTuioBounds(float xp, float yp); + + /** + * The TuioServer prints verbose TUIO event messages to the console if set to true. + * @param verbose print verbose messages if set to true + */ + void setVerbose(bool verbose) { this->verbose=verbose; } + + void setInversion(bool ix, bool iy, bool ia) { + invert_x = ix; + invert_y = iy; + invert_a = ia; + }; + + void setInvertXpos(bool ix) { invert_x = ix; }; + void setInvertYpos(bool iy) { invert_y = iy; }; + void setInvertAngle(bool ia) { invert_a = ia; }; + bool getInvertXpos() { return invert_x; }; + bool getInvertYpos() { return invert_y; }; + bool getInvertAngle() { return invert_a; }; + void resetTuioObjectList(); + + protected: + std::list freePointerList; + std::list freePointerBuffer; + + TuioTime currentFrameTime; + osc::TimeTag frameTimeTag; + unsigned int currentFrame; + unsigned int pointerCount, maxPointerID; + unsigned int sessionID; + + bool tobjUpdate; + bool verbose; + + bool invert_x; + bool invert_y; + bool invert_a; + }; +} +#endif /* INCLUDED_TUIOMANAGER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp new file mode 100644 index 0000000000..15836c1b4f --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp @@ -0,0 +1,311 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioObject.h" + +using namespace TUIO2; + +TuioObject::TuioObject (unsigned int s_id) { + currentTime = TuioTime::getSystemTime(); + session_id = s_id; + startTime = currentTime; + + token = NULL; + pointer = NULL; + bounds = NULL; + symbol = NULL; + state = TUIO_ADDED; +} + +TuioObject::TuioObject (TuioTime ttime, unsigned int s_id) { + currentTime = ttime; + session_id = s_id; + startTime = currentTime; + + token = NULL; + pointer = NULL; + bounds = NULL; + symbol = NULL; + state = TUIO_ADDED; +} + +TuioObject::TuioObject (TuioTime ttime, TuioSource *src, unsigned int s_id) { + currentTime = ttime; + session_id = s_id; + startTime = currentTime; + + setTuioSource(src); + token = NULL; + pointer = NULL; + bounds = NULL; + symbol = NULL; + state = TUIO_ADDED; +} + +TuioObject::~TuioObject() { + deleteAllTuioComponents(); +} + +unsigned int TuioObject::getSessionID() { + return session_id; +} + +void TuioObject::setTuioSource(TuioSource *src) { + source.setSourceString(src->getSourceID(),src->getSourceString()); +} + +TuioSource* TuioObject::getTuioSource() { + return &source; +} + +void TuioObject::setTuioToken (TuioToken *ttok) { + token = ttok; + token->setContainingTuioObject(this); + currentTime = TuioTime::getSystemTime(); + state = TUIO_ADDED; +} + +void TuioObject::setTuioPointer (TuioPointer *tptr) { + pointer = tptr; + pointer->setContainingTuioObject(this); + currentTime = TuioTime::getSystemTime(); + state = TUIO_ADDED; +} + +void TuioObject::setTuioBounds (TuioBounds *tbnd) { + bounds = tbnd; + bounds->setContainingTuioObject(this); + currentTime = TuioTime::getSystemTime(); + state = TUIO_ADDED; +} + +void TuioObject::setTuioSymbol (TuioSymbol *tsym) { + symbol = tsym; + symbol->setContainingTuioObject(this); + currentTime = TuioTime::getSystemTime(); + state = TUIO_ADDED; +} + +void TuioObject::removeAllTuioComponents(TuioTime ttime) { + removeTuioToken(ttime); + removeTuioPointer(ttime); + removeTuioBounds(ttime); + removeTuioSymbol(ttime); +} + +void TuioObject::removeTuioToken (TuioTime ttime) { + if (token != NULL) token->remove(ttime); + currentTime = ttime; + } + +void TuioObject::removeTuioPointer (TuioTime ttime) { + if (pointer != NULL) pointer->remove(ttime); + currentTime = ttime; +} + +void TuioObject::removeTuioBounds (TuioTime ttime) { + if (bounds != NULL) bounds->remove(ttime); + currentTime = ttime; +} + +void TuioObject::removeTuioSymbol (TuioTime ttime) { + if (symbol != NULL) symbol->remove(ttime); + currentTime = ttime; +} + +void TuioObject::deleteAllTuioComponents() { + deleteTuioToken(); + deleteTuioPointer(); + deleteTuioBounds(); + deleteTuioSymbol(); +} + +void TuioObject::deleteTuioToken () { + if (token != NULL) { + delete token; + token = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +void TuioObject::deleteTuioPointer () { + if (pointer != NULL) { + delete pointer; + pointer = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +void TuioObject::deleteTuioBounds () { + if (bounds != NULL) { + delete bounds; + bounds = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +void TuioObject::deleteTuioSymbol () { + if (symbol != NULL) { + delete symbol; + symbol = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +void TuioObject::clearAllTuioComponents() { + clearTuioToken(); + clearTuioPointer(); + clearTuioBounds(); + clearTuioSymbol(); +} + +void TuioObject::clearTuioToken () { + if (token != NULL) { + token = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +void TuioObject::clearTuioPointer () { + if (pointer != NULL) { + pointer = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +void TuioObject::clearTuioBounds () { + if (bounds != NULL) { + bounds = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +void TuioObject::clearTuioSymbol () { + if (symbol != NULL) { + symbol = NULL; + //currentTime = TuioTime::getSessionTime(); + } +} + +bool TuioObject::containsAnyTuioComponent () { + if (token != NULL) return true; + else if (pointer != NULL) return true; + else if (bounds != NULL) return true; + else if (symbol != NULL) return true; + else return false; +} + +bool TuioObject::containsTuioToken () { + if (token != NULL) return true; + else return false; +} + +bool TuioObject::containsTuioPointer () { + if (pointer != NULL) return true; + else return false; +} + +bool TuioObject::containsTuioBounds () { + if (bounds != NULL) return true; + else return false; +} + +bool TuioObject::containsTuioSymbol () { + if (symbol != NULL) return true; + else return false; +} + +bool TuioObject::containsNewTuioToken () { + if (token == NULL) return false; + else if (token->getTuioState()==TUIO_ADDED) return true; + else return false; +} + +bool TuioObject::containsNewTuioPointer () { + if (pointer == NULL) return false; + else if (pointer->getTuioState()==TUIO_ADDED) return true; + else return false; +} + +bool TuioObject::containsNewTuioBounds () { + if (bounds == NULL) return false; + else if (bounds->getTuioState()==TUIO_ADDED) return true; + else return false; +} + +bool TuioObject::containsNewTuioSymbol () { + if (symbol == NULL) return false; + else if (symbol->getTuioState()==TUIO_ADDED) return true; + else return false; +} + +TuioToken* TuioObject::getTuioToken () { + return token; +} + +TuioPointer* TuioObject::getTuioPointer () { + return pointer; +} + +TuioBounds* TuioObject::getTuioBounds () { + return bounds; +} + +TuioSymbol* TuioObject::getTuioSymbol () { + return symbol; +} + +void TuioObject::stop(TuioTime ttime){ + if (token!=NULL) token->stop(ttime); + if (pointer!=NULL) pointer->stop(ttime); + if (bounds!=NULL) bounds->stop(ttime); + currentTime = ttime; +} + +void TuioObject::remove(TuioTime ttime){ + if (token!=NULL) token->remove(ttime); + if (pointer!=NULL) pointer->remove(ttime); + if (bounds!=NULL) bounds->remove(ttime); + currentTime = ttime; + state = TUIO_REMOVED; +} + +void TuioObject::update(TuioTime ttime){ + currentTime = ttime; + state = TUIO_IDLE; +} + +bool TuioObject::isMoving(){ + if ((token!=NULL) && token->isMoving()) return true; + if ((pointer!=NULL) && pointer->isMoving()) return true; + if ((bounds!=NULL) && bounds->isMoving()) return true; + return false; +} + +TuioTime TuioObject::getTuioTime() const{ + return currentTime; +} + +TuioTime TuioObject::getStartTime() const{ + return startTime; +} + +unsigned char TuioObject::getTuioState() const{ + return state; +} + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h new file mode 100644 index 0000000000..4e18103b86 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h @@ -0,0 +1,341 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOOBJECT_H +#define INCLUDED_TUIOOBJECT_H + +#include "TuioTime.h" +#include "TuioToken.h" +#include "TuioPointer.h" +#include "TuioBounds.h" +#include "TuioSymbol.h" +#include "TuioSource.h" + +namespace TUIO2 { + + /** + * The TuioObject class encapsulates all Tuio objects that share the same Session ID. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + + class LIBDECL TuioObject { + + protected: + /** + * The shared session ID + */ + unsigned int session_id; + /** + * The associated TuioSource + */ + TuioSource source; + /** + * the associated TuioToken + */ + TuioToken *token; + /** + * the associated TuioPointer + */ + TuioPointer *pointer; + /** + * the associated TuioBounds + */ + TuioBounds *bounds; + /** + * the associated TuioSymbol + */ + TuioSymbol *symbol; + /** + * The time stamp of the last update represented as TuioTime (time since session start) + */ + TuioTime currentTime; + /** + * The creation time of this TuioObject represented as TuioTime (time since session start) + */ + TuioTime startTime; + /** + * Reflects the current state of the TuioObject + */ + unsigned char state; + + public: + /** + * The default constructor only takes the Session ID + * @param s_id the Session ID to assign + */ + TuioObject (unsigned int s_id); + + /** + * This constructor takes a TuioTime and the Session ID + * @param ttime the TuioTime to assign + * @param s_id the Session ID to assign + */ + TuioObject (TuioTime ttime, unsigned int s_id); + + /** + * This constructor takes a TuioTime and the Session ID + * @param ttime the TuioTime to assign + * @param src the TuioSource to assign + * @param s_id the Session ID to assign + */ + TuioObject (TuioTime ttime, TuioSource *src, unsigned int s_id); + + /** + * The default destructor also delets all assigned TUIO components + */ + ~TuioObject (); + + /** + * Returns the associated Session ID + * @return the associated Session ID + */ + unsigned int getSessionID(); + + /** + * Sets the assotiated TUIO source + * + * @param src the TuioSource to assign + */ + void setTuioSource(TuioSource *src); + + /** + * Returns the associated TUIO source + */ + TuioSource* getTuioSource(); + + /** + * This method assigns a TuioToken to this TuioObject + * @param ttok the TuioToken to assign + */ + void setTuioToken(TuioToken *ttok); + + /** + * This method assigns a TuioPointer to this TuioObject + * @param tptr the TuioPointer to assign + */ + void setTuioPointer(TuioPointer *tptr); + + /** + * This method assigns a TuioBounds to this TuioObject + * @param tbnd the TuioBounds to assign + */ + void setTuioBounds(TuioBounds *tbnd); + + /** + * This method assigns a TuioSymbol to this TuioObject + * @param tsym the TuioSymbol to assign + */ + void setTuioSymbol(TuioSymbol *tsym); + + /** + * This method sets all TuioComponents in this TuioObject to TUIO_REMOVED state + */ + void removeAllTuioComponents(TuioTime ttime); + + /** + * This method sets the TuioToken in this TuioObject to TUIO_REMOVED state + */ + void removeTuioToken(TuioTime ttime); + + /** + * This method sets the TuioPointer in this TuioObject to TUIO_REMOVED state + */ + void removeTuioPointer(TuioTime ttime); + + /** + * This method sets the TuioBounds in this TuioObject to TUIO_REMOVED state + */ + void removeTuioBounds(TuioTime ttime); + + /** + * This method sets the TuioSymbol in this TuioObject to TUIO_REMOVED state + */ + void removeTuioSymbol(TuioTime ttime); + + /** + * This method deletes all TuioComponents in this TuioObject + */ + void deleteAllTuioComponents(); + + /** + * This method deletes the TuioToken in this TuioObject + */ + void deleteTuioToken(); + + /** + * This method deletes the TuioPointer in this TuioObject + */ + void deleteTuioPointer(); + + /** + * This method deletes the TuioBounds in this TuioObject + */ + void deleteTuioBounds(); + + /** + * This method deletes the TuioSymbol in this TuioObject + */ + void deleteTuioSymbol(); + + /** + * This method clears all TuioComponents in this TuioObject + */ + void clearAllTuioComponents(); + + /** + * This method clears the TuioToken in this TuioObject + */ + void clearTuioToken(); + + /** + * This method clears the TuioPointer in this TuioObject + */ + void clearTuioPointer(); + + /** + * This method clears the TuioBounds in this TuioObject + */ + void clearTuioBounds(); + + /** + * This method clears the TuioSymbol in this TuioObject + */ + void clearTuioSymbol(); + + /** + * This method tests for any TuioComponent in this TuioObject + * @return true if any TuioComponent has been assigned + */ + bool containsAnyTuioComponent(); + + /** + * This method tests for a TuioToken in this TuioObject + * @return true if a TuioToken has been assigned + */ + bool containsTuioToken(); + + /** + * This method tests for a TuioPointer in this TuioObject + * @return true if a TuioPointer has been assigned + */ + bool containsTuioPointer(); + + /** + * This method tests for a TuioBounds in this TuioObject + * @return true if a TuioBounds has been assigned + */ + bool containsTuioBounds(); + + /** + * This method tests for a TuioSymbol in this TuioObject + * @return true if a TuioSymbol has been assigned + */ + bool containsTuioSymbol(); + + /** + * This method tests if a new TuioToken has been added to this TuioObject + * @return true if a TuioToken has been added + */ + bool containsNewTuioToken(); + + /** + * This method tests if a new TuioPointer has been added this TuioObject + * @return true if a TuioPointer has been added + */ + bool containsNewTuioPointer(); + + /** + * This method tests if a new TuioBounds has been added to this TuioObject + * @return true if a TuioBounds has been added + */ + bool containsNewTuioBounds(); + + /** + * This method tests if a new TuioSymbol has beed added to this TuioObject + * @return true if a TuioSymbol has been added + */ + bool containsNewTuioSymbol(); + + /** + * This method returns the TuioToken associated to this TuioObject + * @return the associated TuioToken + */ + TuioToken* getTuioToken(); + + /** + * This method returns the TuioPointer associated to this TuioObject + * @return the associated TuioPointer + */ + TuioPointer* getTuioPointer(); + + /** + * This method returns the TuioBounds associated to this TuioObject + * @return the associated TuioBounds + */ + TuioBounds* getTuioBounds(); + + /** + * This method returns the TuioSymbol associated to this TuioObject + * @return the associated TuioSymbol + */ + TuioSymbol* getTuioSymbol(); + + /** + * This method stops all encapsulated TuioComponents + */ + void stop(TuioTime ttime); + + /** + * This method removes all encapsulated TuioComponents + */ + void remove(TuioTime ttime); + + /** + * This method returns true if any encapsulated TuioComponent is moving + */ + bool isMoving(); + + /** + * This method refreshes the currentTime after an update + */ + void update(TuioTime ttime); + + /** + * Returns current time stamp of this TuioPoint as TuioTime + * + * @return the time stamp of this TuioPoint as TuioTime + */ + TuioTime getTuioTime() const; + + /** + * Returns the start time of this TuioPoint as TuioTime. + * + * @return the start time of this TuioPoint as TuioTime + */ + TuioTime getStartTime() const; + + /** + * Returns the TUIO state of this TuioObject. + * @return the TUIO state of this TuioObject + */ + unsigned char getTuioState() const; + }; +} +#endif // INCLUDED_TUIOOBJECT_H diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.cpp new file mode 100644 index 0000000000..935a63db77 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.cpp @@ -0,0 +1,124 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioPoint.h" + +using namespace TUIO2; + +TuioPoint::TuioPoint (float xp, float yp) { + xpos = xp; + ypos = yp; + currentTime = TuioTime::getSystemTime(); + startTime = currentTime; +} + +TuioPoint::TuioPoint (TuioTime ttime, float xp, float yp) { + xpos = xp; + ypos = yp; + currentTime = ttime; + startTime = currentTime; +} + +TuioPoint::TuioPoint (TuioPoint *tpoint) { + xpos = tpoint->getX(); + ypos = tpoint->getY(); + currentTime = TuioTime::getSystemTime(); + startTime = currentTime; +} + +void TuioPoint::update (TuioPoint *tpoint) { + xpos = tpoint->getX(); + ypos = tpoint->getY(); +} + +void TuioPoint::update (float xp, float yp) { + xpos = xp; + ypos = yp; +} + +void TuioPoint::update (TuioTime ttime, float xp, float yp) { + xpos = xp; + ypos = yp; + currentTime = ttime; +} + + +float TuioPoint::getX() const{ + return xpos; +} + +float TuioPoint::getY() const{ + return ypos; +} + +float TuioPoint::getDistance(float xp, float yp) const{ + float dx = xpos-xp; + float dy = ypos-yp; + return sqrtf(dx*dx+dy*dy); +} + +float TuioPoint::getScreenDistance(float xp, float yp, int w, int h) const{ + float dx = w*xpos-w*xp; + float dy = h*ypos-h*yp; + return sqrtf(dx*dx+dy*dy); +} + +float TuioPoint::getDistance(TuioPoint *tpoint) const{ + return getDistance(tpoint->getX(),tpoint->getY()); +} + + +float TuioPoint::getAngle(float xp, float yp) const{ + float side = xpos-xp; + float height = ypos-yp; + float distance = getDistance(xp,yp); + + float angle = (float)(asin(side/distance)+M_PI/2); + if (height<0) angle = 2.0f*(float)M_PI-angle; + + return angle; +} + +float TuioPoint::getAngle(TuioPoint *tpoint) const{ + return getAngle(tpoint->getX(),tpoint->getY()); +} + +float TuioPoint::getAngleDegrees(float xp, float yp) const{ + return ((getAngle(xp,yp)/(float)M_PI)*180.0f); +} + +float TuioPoint::getAngleDegrees(TuioPoint *tpoint) const{ + return ((getAngle(tpoint)/(float)M_PI)*180.0f); +} + +int TuioPoint::getScreenX(int width) const{ + return (int)floor(xpos*width+0.5f); +} + +int TuioPoint::getScreenY(int height) const{ + return (int)floor(ypos*height+0.5f); +} + +TuioTime TuioPoint::getTuioTime() const{ + return currentTime; +} + +TuioTime TuioPoint::getStartTime() const{ + return startTime; +} + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h b/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h new file mode 100644 index 0000000000..a66730eb64 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h @@ -0,0 +1,213 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOPOINT_H +#define INCLUDED_TUIOPOINT_H + +#include "TuioTime.h" +#include "limits.h" +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +namespace TUIO2 { + + /** + * The TuioPoint class on the one hand is a simple tobj and utility class to handle TUIO positions in general, + * on the other hand the TuioPoint is the base class for the TuioPointer and TuioToken classes. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioPoint { + + protected: + /** + * X coordinate, representated as a floating point value in a range of 0..1 + */ + float xpos; + /** + * X coordinate, representated as a floating point value in a range of 0..1 + */ + float ypos; + /** + * The time stamp of the last update represented as TuioTime (time since session start) + */ + TuioTime currentTime; + /** + * The creation time of this TuioPoint represented as TuioTime (time since session start) + */ + TuioTime startTime; + + public: + /** + * This constructor takes two floating point coordinate arguments + * and sets the coordinate attributes to these values. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + TuioPoint (float xp, float yp); + + /** + * This constructor takes a TuioTime object and two floating point coordinate arguments and sets + * its coordinate attributes to these values and its time stamp to the provided TUIO time object. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + TuioPoint (TuioTime ttime, float xp, float yp); + + /** + * This constructor takes a TuioPoint argument and sets its coordinate attributes + * to the coordinates of the provided TuioPoint and its time stamp to the current session time. + * + * @param tpoint the TuioPoint to assign + */ + TuioPoint (TuioPoint *tpoint); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioPoint(){}; + + /** + * Takes a TuioPoint argument and updates its coordinate attributes + * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. + * + * @param tpoint the TuioPoint to assign + */ + void update (TuioPoint *tpoint); + + /** + * Takes two floating point coordinate arguments and updates its coordinate attributes + * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + void update (float xp, float yp); + + /** + * Takes a TuioTime object and two floating point coordinate arguments and updates its coordinate attributes + * to the coordinates of the provided TuioPoint and its time stamp to the provided TUIO time object. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + void update (TuioTime ttime, float xp, float yp); + + /** + * Returns the X coordinate of this TuioPoint. + * @return the X coordinate of this TuioPoint + */ + float getX() const; + + /** + * Returns the Y coordinate of this TuioPoint. + * @return the Y coordinate of this TuioPoint + */ + float getY() const; + + /** + * Returns the distance to the provided coordinates + * + * @param xp the X coordinate of the distant point + * @param yp the Y coordinate of the distant point + * @return the distance to the provided coordinates + */ + float getDistance(float xp, float yp) const; + + /** + * Returns the distance to the provided coordinates + * + * @param xp the X coordinate of the distant point + * @param yp the Y coordinate of the distant point + * @return the distance to the provided coordinates + */ + float getScreenDistance(float xp, float yp, int w, int h) const; + /** + * Returns the distance to the provided TuioPoint + * + * @param tpoint the distant TuioPoint + * @return the distance to the provided TuioPoint + */ + float getDistance(TuioPoint *tpoint) const; + /** + * Returns the angle to the provided coordinates + * + * @param xp the X coordinate of the distant point + * @param yp the Y coordinate of the distant point + * @return the angle to the provided coordinates + */ + float getAngle(float xp, float yp) const; + /** + * Returns the angle to the provided TuioPoint + * + * @param tpoint the distant TuioPoint + * @return the angle to the provided TuioPoint + */ + float getAngle(TuioPoint *tpoint) const; + /** + * Returns the angle in degrees to the provided coordinates + * + * @param xp the X coordinate of the distant point + * @param yp the Y coordinate of the distant point + * @return the angle in degrees to the provided TuioPoint + */ + float getAngleDegrees(float xp, float yp) const; + /** + * Returns the angle in degrees to the provided TuioPoint + * + * @param tpoint the distant TuioPoint + * @return the angle in degrees to the provided TuioPoint + */ + float getAngleDegrees(TuioPoint *tpoint) const; + /** + * Returns the X coordinate in pixels relative to the provided screen width. + * + * @param width the screen width + * @return the X coordinate of this TuioPoint in pixels relative to the provided screen width + */ + int getScreenX(int width) const; + /* + * Returns the Y coordinate in pixels relative to the provided screen height. + * + * @param height the screen height + * @return the Y coordinate of this TuioPoint in pixels relative to the provided screen height + */ + int getScreenY(int height) const; + /** + * Returns current time stamp of this TuioPoint as TuioTime + * + * @return the time stamp of this TuioPoint as TuioTime + */ + TuioTime getTuioTime() const; + /** + * Returns the start time of this TuioPoint as TuioTime. + * + * @return the start time of this TuioPoint as TuioTime + */ + TuioTime getStartTime() const; + }; +} +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp new file mode 100644 index 0000000000..ffdb5066da --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp @@ -0,0 +1,132 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioPointer.h" + +using namespace TUIO2; + +TuioPointer::TuioPointer (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p):TuioComponent(ttime,tobj,xp,yp,a) { + type_id = ti; + user_id = ui; + pointer_id = pi; + shear = sa; + radius = r; + pressure = p; +} + +TuioPointer::TuioPointer (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p):TuioComponent(tobj,xp,yp,a) { + type_id = ti; + user_id = ui; + shear = sa; + pointer_id = pi; + radius = r; + pressure = p; +} + +TuioPointer::TuioPointer (TuioObject *tobj, unsigned int pi, float xp, float yp, float a, float sa, float r, float p):TuioComponent(tobj,xp,yp,a) { + type_id = 0; + user_id = 0; + pointer_id = pi; + shear = sa; + radius = r; + pressure = p; +} + +TuioPointer::TuioPointer (TuioPointer *tptr):TuioComponent(tptr) { + pointer_id = tptr->getPointerID(); + type_id = tptr->getTypeID(); + user_id = tptr->getUserID(); + shear = tptr->getShear(); + radius = tptr->getRadius(); + pressure = tptr->getPressure(); +} + +void TuioPointer::update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa) { + TuioComponent::update(ttime,xp,yp,a,xs,ys,0,ma,0); + shear = sa; + radius = r; + pressure = p; + pressure_speed = ps; + pressure_accel = pa; +} + +void TuioPointer::update (float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa) { + TuioComponent::update(xp,yp,a,xs,ys,0,ma,0); + shear = sa; + radius = r; + pressure = p; + pressure_speed = ps; + pressure_accel = pa; +} + +void TuioPointer::update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p) { + TuioComponent::update(ttime,xp,yp,a); + shear = sa; + radius = r; + pressure = p; +} + +void TuioPointer::update (TuioPointer *tptr) { + TuioComponent::update(tptr); + shear = tptr->getShear(); + radius = tptr->getRadius(); + pressure = tptr->getPressure(); +} + +unsigned int TuioPointer::getPointerID() const{ + return pointer_id; +}; + +unsigned short TuioPointer::getTypeID() const{ + return type_id; +}; + +unsigned short TuioPointer::getUserID() const{ + return user_id; +}; + +unsigned int TuioPointer::getTypeUserID() const { + int tu_id = user_id << 16 | type_id; + return tu_id; +} + +void TuioPointer::setTypeUserID(unsigned int tu_id) { + user_id = tu_id >> 16; + type_id = tu_id & 0x0000FFFF; +} + +float TuioPointer::getShear() const{ + return shear; +}; + +float TuioPointer::getRadius() const{ + return radius; +}; + +float TuioPointer::getPressure() const{ + return pressure; +}; + +float TuioPointer::getPressureSpeed() const{ + return pressure_speed; +} + +float TuioPointer::getPressureAccel() const{ + return pressure_accel; +} + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h b/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h new file mode 100644 index 0000000000..43ffe72caf --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h @@ -0,0 +1,263 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOPOINTER_H +#define INCLUDED_TUIOPOINTER_H + +#include "TuioComponent.h" + +namespace TUIO2 { + + /** + * The TuioPointer class encapsulates /tuio2/ptr TUIO pointers. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + + class LIBDECL TuioPointer: public TuioComponent { + + protected: + /** + * The individual pointer ID number that is assigned to each TuioPointer. + */ + unsigned int pointer_id; + + /** + * The pointer type ID that is assigned to each TuioPointer. + */ + unsigned short type_id; + + /** + * The user ID that is assigned to each TuioPointer. + */ + unsigned short user_id; + + /** + * The shear angle that is assigned to each TuioPointer. + */ + float shear; + + /** + * The action radius that is assigned to each TuioPointer. + */ + float radius; + + /** + * The pressure that is assigned to each TuioPointer. + */ + float pressure; + + /** + * The pressure speed value. + */ + float pressure_speed; + + /** + * The pressure acceleration value. + */ + float pressure_accel; + + public: + using TuioComponent::update; + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, Pointer ID, X and Y coordinate to the newly created TuioPointer. + * + * @param ttime the TuioTime to assign + * @param tobj the TuioObject to assign + * @param ti the Type ID to assign + * @param ui the User ID to assign + * @param pi the Pointer ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param sa the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + */ + TuioPointer (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p); + + /** + * This constructor takes the provided Session ID, Pointer ID, X and Y coordinate + * and assigs these values to the newly created TuioPointer. + * + * @param tobj the TuioObject to assign + * @param ti the Type ID to assign + * @param ui the User ID to assign + * @param pi the Pointer ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param sa the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + */ + TuioPointer (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p); + + + /** + * This constructor takes the provided Session ID, Pointer ID, X and Y coordinate + * and assigs these values to the newly created TuioPointer. + * + * @param tobj the TuioObject to assign + * @param pi the Pointer ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param sa the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + */ + TuioPointer (TuioObject *tobj, unsigned int pi, float xp, float yp, float a, float sa, float r, float p); + + /** + * This constructor takes the atttibutes of the provided TuioPointer + * and assigs these values to the newly created TuioPointer. + * + * @param tptr the TuioPointer to assign + */ + TuioPointer (TuioPointer *tptr); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioPointer(){}; + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate, width, pressure, X and Y velocity, motion acceleration, + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param sa the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param ps the pressure velocity to assign + * @param ma the motion acceleration to assign + * @param pa the pressure acceleration to assign + */ + void update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa); + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate, width, pressure, X and Y velocity, motion acceleration, + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param sa the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param ps the pressure velocity to assign + * @param ma the motion acceleration to assign + * @param pa the pressure acceleration to assign + */ + void update (float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa); + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate and angle to the private TuioToken attributes. + * The speed and accleration values are calculated accordingly. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param sa the shear angle to assign + * @param r the radius to assign + * @param p the pressure to assign + */ + void update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p); + + /** + * Takes the atttibutes of the provided TuioPointer + * and assigs these values to this TuioPointer. + * The TuioTime time stamp of this TuioComponent remains unchanged. + * + * @param ttok the TuioComponent to assign + */ + void update (TuioPointer *tptr); + + /** + * Returns the Pointer ID of this TuioPointer. + * @return the Pointer ID of this TuioPointer + */ + unsigned int getPointerID() const; + + /** + * Returns the Type ID of this TuioPointer. + * @return the Type ID of this TuioPointer + */ + unsigned short getTypeID() const; + + /** + * Returns the User ID of this TuioPointer. + * @return the User ID of this TuioPointer + */ + unsigned short getUserID() const; + + /** + * Returns the encoded Type & User ID of this TuioPointer. + * @return the encoded Type & User ID of this TuioPointer + */ + unsigned int getTypeUserID() const; + + /** + * Decodes and assigns the Type & User ID to this TuioPointer. + * @param tu_id the encoded Type & User ID of this TuioPointer + */ + void setTypeUserID(unsigned int tu_id); + + /** + * Returns the shear angle of this TuioPointer. + * @return the shear angle of this TuioPointer + */ + float getShear() const; + + /** + * Returns the action radius of this TuioPointer. + * @return the action radius of this TuioPointer + */ + float getRadius() const; + + /** + * Returns the Pressure of this TuioPointer. + * @return the Pressure of this TuioPointer + */ + float getPressure() const; + + /** + * Returns the pressure speed of this TuioPointer. + * @return the pressure speed of this TuioPointer + */ + float getPressureSpeed() const; + + /** + * Returns the pressure acceleration of this TuioPointer. + * @return the pressure acceleration of this TuioPointer + */ + float getPressureAccel() const; + }; +} +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp new file mode 100644 index 0000000000..9d599f774f --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp @@ -0,0 +1,329 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioServer.h" +#include "UdpSender.h" + +using namespace TUIO2; +using namespace osc; + +TuioServer::TuioServer() + :local_sender (true) + ,full_update (false) + ,periodic_update (false) + ,source (NULL) +{ + primary_sender = new UdpSender(); + initialize(); +} + +TuioServer::TuioServer(const char *host, unsigned short port) +:local_sender (true) +,full_update (false) +,periodic_update (false) +,source (NULL) +{ + primary_sender = new UdpSender(host,port); + initialize(); +} + +TuioServer::TuioServer(OscSender *oscsend) + :primary_sender (oscsend) + ,local_sender (false) + ,full_update (false) + ,periodic_update (false) + ,source (NULL) +{ + initialize(); +} + +void TuioServer::initialize() { + + senderList.push_back(primary_sender); + int size = primary_sender->getBufferSize(); + oscBuffer = new char[size]; + oscPacket = new osc::OutboundPacketStream(oscBuffer,size); + fullBuffer = new char[size]; + fullPacket = new osc::OutboundPacketStream(oscBuffer,size); + + updateTime = TuioTime(currentFrameTime); + //sendEmptyTuioBundle(); + + invert_x = false; + invert_y = false; + invert_a = false; +} + +TuioServer::~TuioServer() { + + initTuioFrame(TuioTime::getSystemTime()); + stopUntouchedMovingObjects(); + + initTuioFrame(TuioTime::getSystemTime()); + removeUntouchedStoppedObjects(); + sendEmptyTuioBundle(); + + delete []oscBuffer; + delete oscPacket; + delete []fullBuffer; + delete fullPacket; + + if (local_sender) delete primary_sender; +} + +void TuioServer::addOscSender(OscSender *sender) { + + // add source address if previously local + /*if ((source_name) && (primary_sender->isLocal()) && (senderList.size()==1)) { + setSourceName(source_name); + }*/ + + // resize packets to smallest transport method + unsigned int size = sender->getBufferSize(); + if (sizeCapacity()) { + osc::OutboundPacketStream *temp = oscPacket; + oscPacket = new osc::OutboundPacketStream(oscBuffer,size); + delete temp; + temp = fullPacket; + fullPacket = new osc::OutboundPacketStream(oscBuffer,size); + delete temp; + + } + + senderList.push_back(sender); +} + +void TuioServer::deliverOscPacket(osc::OutboundPacketStream *packet) { + + for (unsigned int i=0;isendOscPacket(packet); +} + +void TuioServer::setSourceName(const char* name) { + if (source==NULL) source = new TuioSource(name); + //else source->setSourceName(name); +} + +void TuioServer::setDimension(unsigned short w, unsigned short h) { + if (source!=NULL) source->setDimension(w,h); + + // decoder test + /*int dim = source->getDimension(); + short width = dim >> 16; + short height = dim & 0x0000FFFF; + printf("dim: %i %i\n",width,height);*/ +} + +void TuioServer::commitTuioFrame() { + TuioManager::commitTuioFrame(); + + if(tobjUpdate) { + startTuioBundle(currentFrame); + for (std::list::iterator tobj = tobjList.begin(); tobj!=tobjList.end(); tobj++) { + + if ((*tobj)->containsTuioToken()) { + TuioToken *ttok = (*tobj)->getTuioToken(); + if ((full_update) || (ttok->getTuioTime()==currentFrameTime)) addTokenMessage(ttok); + } + + if ((*tobj)->containsTuioPointer()) { + TuioPointer *tptr = (*tobj)->getTuioPointer(); + if ((full_update) || (tptr->getTuioTime()==currentFrameTime)) addPointerMessage(tptr); + } + + if ((*tobj)->containsTuioBounds()) { + TuioBounds *tbnd = (*tobj)->getTuioBounds(); + if ((full_update) || (tbnd->getTuioTime()==currentFrameTime)) addBoundsMessage(tbnd); + } + + if ((*tobj)->containsTuioSymbol()) { + TuioSymbol *tsym = (*tobj)->getTuioSymbol(); + if ((full_update) || (tsym->getTuioTime()==currentFrameTime)) addSymbolMessage(tsym); + } + + + } + updateTime = TuioTime(currentFrameTime); + sendTuioBundle(); + } else if (periodic_update) { + + TuioTime timeCheck = currentFrameTime - updateTime; + if(timeCheck.getSeconds()>=update_interval) { + updateTime = TuioTime(currentFrameTime); + startTuioBundle(currentFrame); + if (full_update) { + for (std::list::iterator tobj = tobjList.begin(); tobj!=tobjList.end(); tobj++) { + // start a new packet if we exceed the packet capacity + if ((oscPacket->Capacity()-oscPacket->Size())getTuioToken()); + } + } + sendTuioBundle(); + } + } + tobjUpdate = false; +} + +void TuioServer::sendEmptyTuioBundle() { + oscPacket->Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + (*oscPacket) << osc::BeginMessage( "/tuio2/frm") << 0 << TuioTime::getSystemTimeTag() << (int32)source->getDimension() << source->getSourceName() << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio2/alv") << osc::EndMessage; + (*oscPacket) << osc::EndBundle; + deliverOscPacket( oscPacket ); +} + +void TuioServer::sendFullTuioBundle() { + +} + +void TuioServer::checkBundleCapacity(int msg_size) { + + int size = msg_size + ALV_MESSAGE_SIZE + 4*tobjList.size(); + + if ((oscPacket->Capacity()-oscPacket->Size())Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + if (source) (*oscPacket) << osc::BeginMessage( "/tuio2/frm") << (int32)currentFrame << frameTimeTag << (int32)source->getDimension() << source->getSourceName(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::addTokenMessage(TuioToken *ttok) { + + // start a new packet if we exceed the packet capacity + checkBundleCapacity(TOK_MESSAGE_SIZE); + + float xpos = ttok->getX(); + float xvel = ttok->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = ttok->getY(); + float yvel = ttok->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + float angle = ttok->getAngle(); + float rvel = ttok->getRotationSpeed(); + if (invert_a) { + angle = 2.0f*(float)M_PI - angle; + rvel = -1 * rvel; + } + + (*oscPacket) << osc::BeginMessage( "/tuio2/tok"); + (*oscPacket) << (int32)ttok->getSessionID() << (int32)ttok->getTypeUserID() << (int32)ttok->getSymbolID() << xpos << ypos << angle; + (*oscPacket) << xvel << yvel << rvel << ttok->getMotionAccel() << ttok->getRotationAccel(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::addPointerMessage(TuioPointer *tptr) { + + // start a new packet if we exceed the packet capacity + checkBundleCapacity(PTR_MESSAGE_SIZE); + + float xpos = tptr->getX(); + float xvel = tptr->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = tptr->getY(); + float yvel = tptr->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + + (*oscPacket) << osc::BeginMessage( "/tuio2/ptr"); + (*oscPacket) << (int32)tptr->getSessionID() << (int32)tptr->getTypeUserID() << (int32)tptr->getPointerID(); + (*oscPacket) << xpos << ypos << tptr->getAngle() << tptr->getShear() << tptr->getRadius() << tptr->getPressure(); + (*oscPacket) << xvel << yvel << tptr->getPressureSpeed() << tptr->getMotionAccel() << tptr->getPressureAccel(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::addBoundsMessage(TuioBounds *tbnd) { + + // start a new packet if we exceed the packet capacity + checkBundleCapacity(BND_MESSAGE_SIZE); + + float xpos = tbnd->getX(); + float xvel = tbnd->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = tbnd->getY(); + float yvel = tbnd->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + float angle = tbnd->getAngle(); + float rvel = tbnd->getRotationSpeed(); + if (invert_a) { + angle = 2.0f*(float)M_PI - angle; + rvel = -1 * rvel; + } + + (*oscPacket) << osc::BeginMessage( "/tuio2/bnd"); + (*oscPacket) << (int32)tbnd->getSessionID() << xpos << ypos << angle << tbnd->getWidth() << tbnd->getHeight() << tbnd->getArea(); + (*oscPacket) << xvel << yvel << rvel << tbnd->getMotionAccel() << tbnd->getRotationAccel(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::addSymbolMessage(TuioSymbol *tsym) { + + // start a new packet if we exceed the packet capacity + checkBundleCapacity(SYM_MESSAGE_SIZE); + + (*oscPacket) << osc::BeginMessage( "/tuio2/sym"); + (*oscPacket) << (int32)tsym->getSessionID() << (int32)tsym->getTypeUserID() << (int32)tsym->getSymbolID(); + (*oscPacket) << tsym->getSymbolType() << tsym->getSymbolData(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::sendTuioBundle() { + + //int before = oscPacket->Capacity()-oscPacket->Size(); + (*oscPacket) << osc::BeginMessage( "/tuio2/alv"); + + for(std::list::iterator tobj = tobjList.begin();tobj!= tobjList.end(); tobj++) + (*oscPacket) << (int32)(*tobj)->getSessionID(); + + (*oscPacket) << osc::EndMessage; + //int after = oscPacket->Capacity()-oscPacket->Size(); + //printf("ALV_MESSAGE_SIZE: %i\n",before-after); + + (*oscPacket) << osc::EndBundle; + deliverOscPacket( oscPacket ); +} + + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioServer.h b/modules/touch/ext/libTUIO2/TUIO2/TuioServer.h new file mode 100644 index 0000000000..fc93f8b739 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioServer.h @@ -0,0 +1,210 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOSERVER_H +#define INCLUDED_TUIOSERVER_H + +#include "TuioManager.h" +#include "UdpSender.h" +#include +#include +#include +#ifndef WIN32 +#include +#include +#include +#endif + +#define TOK_MESSAGE_SIZE 108 +#define PTR_MESSAGE_SIZE 68 +#define BND_MESSAGE_SIZE 116 +#define SYM_MESSAGE_SIZE 116 +#define ALV_MESSAGE_SIZE 20 + +namespace TUIO2 { + /** + *

The TuioServer class is the central TUIO protocol encoder component. + * In order to encode and send TUIO messages an instance of TuioServer needs to be created. The TuioServer instance then generates TUIO messages + * which are deliverered by the provided OSCSender. The shown UDPSender send OSC to UDP port 3333 on localhost or to the configured host and port.

+ *

During runtime the each frame is marked with the initFrame and commitFrame methods, + * while the currently present TuioTokens are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

+ *

See the SimpleSimulator example project for further hints on how to use the TuioServer class and its various methods. + *

+ * OscSender *sender = new UDPSender();
+ * TuioServer *server = new TuioServer(sender);
+ * server->setSource(src); // passes a TuioSource* argument
+ * ...
+ * server->initTuioFrame(TuioTime::getSessionTime());
+ * TuioToken *ttok = server->addTuioToken(xpos,ypos,angle);
+ * TuioPointer *tptr = server->addTuioPointer(xpos,ypos,width,pressure);
+ * TuioBounds *tbnd = server->addTuioBounds(xpos,ypos,angle,width,height,area);
+ * server->commitTuioFrame();
+ * ...
+ * server->initTuioFrame(TuioTime::getSessionTime());
+ * server->updateTuioToken(ttok,xpos,ypos,angle);
+ * server->updateTuioPointer(tptr,xpos,ypos,width,pressure);
+ * server->updateTuioBounds(tbnd,xpos,ypos,angle,width,height,area);
+ * server->commitTuioFrame();
+ * ...
+ * server->initTuioFrame(TuioTime::getSessionTime());
+ * server->removeTuioToken(ttok);
+ * server->removeTuioPointer(tptr);
+ * server->removeTuioBounds(tbnd);
+ * server->commitTuioFrame();
+ *

+ * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioServer : public TuioManager { + + public: + + /** + * This constructor creates a TuioServer that uses an internal UdpSender delivering the OSC data via UDP port 3333 on localhost + */ + TuioServer(); + + /** + * This constructor creates a TuioServer that uses an internal UdpSender delivering the OSC data via the provided UDP port on the provided host + * + * @param host the host name for UDP deleivery + * @param port the UDP port number on the provided host + */ + TuioServer(const char *host, unsigned short port); + + /** + * This constructor creates a TuioServer that sends OSC data using the provided OscSender + * + * @param sender the OscSender used for OSC data delivery + */ + TuioServer(OscSender *sender); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioServer(); + + /** + * Generates and sends TUIO messages of all currently active TUIO Components + */ + void sendFullTuioBundle(); + + /** + * Enables the full update of all currently active and inactive TUIO Components + * + */ + void enableFullUpdate() { + full_update = true; + } + + /** + * Disables the full update of all currently active and inactive TUIO Components + */ + void disableFullUpdate() { + full_update = false; + } + + /** + * Returns true if the full update of all currently active TUIO Components is enabled. + * @return true if the full update of all currently active TUIO Components is enabled + */ + bool fullUpdateEnabled() { + return full_update; + } + + /** + * Disables the periodic full update of all currently active TUIO Components + * + * @param interval update interval in seconds, defaults to one second + */ + void enablePeriodicMessages(int interval=1) { + periodic_update = true; + update_interval = interval; + } + + /** + * Disables the periodic full update of all currently active and inactive TUIO Components + */ + void disablePeriodicMessages() { + periodic_update = false; + } + + /** + * Returns true if the periodic update of all currently active TUIO Components is enabled. + * @return true if the periodic update of all currently active TUIO Components is enabled + */ + bool periodicMessagesEnabled() { + return periodic_update; + } + + /** + * Returns the periodic update interval in seconds. + * @return the periodic update interval in seconds + */ + int getUpdateInterval() { + return update_interval; + } + + /** + * Commits the current frame. + * Generates and sends TUIO messages of all currently active and updated TUIO Components. + */ + void commitTuioFrame(); + + /** + * Creates the TuioSource that is transmitted within the /tuio2/frm source attributes. + * + * @param name the source name to assign + */ + void setSourceName(const char* name); + void setDimension(unsigned short w, unsigned short h); + + void addOscSender(OscSender *sender); + + private: + + void initialize(); + + OscSender *primary_sender; + bool local_sender; + + std::vector senderList; + void deliverOscPacket(osc::OutboundPacketStream *packet); + + osc::OutboundPacketStream *oscPacket; + char *oscBuffer; + osc::OutboundPacketStream *fullPacket; + char *fullBuffer; + + void checkBundleCapacity(int size); + void startTuioBundle(unsigned int fseq); + void addTokenMessage(TuioToken *ttok); + void addPointerMessage(TuioPointer *tptr); + void addBoundsMessage(TuioBounds *tbnd); + void addSymbolMessage(TuioSymbol *tsym); + void sendTuioBundle(); + void sendEmptyTuioBundle(); + + int update_interval; + bool full_update, periodic_update; + TuioTime updateTime; + TuioSource *source; + }; +} +#endif /* INCLUDED_TUIOSERVER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioSource.h b/modules/touch/ext/libTUIO2/TUIO2/TuioSource.h new file mode 100644 index 0000000000..2bf5593a07 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioSource.h @@ -0,0 +1,244 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. + */ + +#ifndef INCLUDED_TUIOSOURCE_H +#define INCLUDED_TUIOSOURCE_H + +#include +#include +#include +#include + +namespace TUIO2 { + + /** + * The TuioSource class encapsulates the meta data for the TUIO source attributes provided in /tuio2/frm. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + + class LIBDECL TuioSource { + + protected: + /** + * The ID of the TUIO source + */ + unsigned int source_id; + /** + * The name of the TUIO source + */ + std::string source_name; + /** + * The instance of the TUIO source + */ + unsigned int source_instance; + /** + * The address of the TUIO source + */ + std::string source_address; + /** + * The encoded sensor dimension + */ + unsigned int dimension; + /** + * The TuioTime of the last frame + */ + TuioTime frameTime; + + public: + + /** + * Sets the ID, name and address of the TUIO source + */ + TuioSource() { + source_id = 0; + source_name = "default"; + source_instance = 0; + source_address = "localhost"; + dimension = 0; + }; + + /** + * Sets the ID, name and address of the TUIO source + * + * @param src_name the name of the TUIO source + */ + TuioSource(std::string src_name) { + source_id = 0; + source_name = src_name; + source_instance = 0; + source_address = "localhost"; + dimension = 0; + }; + + /** + * Sets the ID, name and address of the TUIO source + * + * @param src_name the name of the TUIO source + */ + TuioSource(unsigned int sid, std::string src_string, unsigned int dim) { + source_id = sid; + setSourceString(src_string); + setDimension(dim); + }; + + /** + * Sets the ID, name and address of the TUIO source + * + * @param src_name the name of the TUIO source + * @param src_inst the instance of the TUIO source + * @param src_addr the address of the TUIO source + */ + TuioSource(std::string src_name, unsigned int src_inst, std::string src_addr) { + source_id = 0; + source_name = src_name; + source_instance = src_inst; + source_address = src_addr; + }; + + /** + * Sets the ID, name and address of the TUIO source + * + * @param src_id the ID of the TUIO source + * @param src_name the name of the TUIO source + * @param src_inst the instance of the TUIO source + * @param src_addr the address of the TUIO source + */ + TuioSource(unsigned int src_id, std::string src_name, unsigned int src_inst, std::string src_addr) { + source_id = src_id; + source_name = src_name; + source_instance = src_inst; + source_address = src_addr; + }; + + ~TuioSource() {}; + + void setSourceString(std::string src_string) { + + if (src_string.length()==0) return; + char *data = strdup(src_string.c_str()); + + char *name_inst = strtok(data, "@"); + + char *addr = strtok(NULL, "@"); + if (addr!=NULL) source_address = std::string(addr); + else source_address = (char*)"0x7F000001"; + + char *name = strtok(name_inst, ":"); + source_name = std::string(name); + + char *inst = strtok(NULL, ":"); + if (inst!=NULL) source_instance = atoi(inst); + else source_instance = 0; + } + + void setSourceString(unsigned int src_id, std::string src_string) { + + source_id = src_id; + setSourceString(src_string); + } + + std::string getSourceString() { + + std::stringstream src_stream; + src_stream << source_name << ":" << source_instance << "@" << source_address; + return src_stream.str(); + } + + /** + * Returns the ID of the TUIO source + */ + unsigned int getSourceID() { return source_id; } + + /** + * Returns the name of the TUIO source + */ + const char* getSourceName() { return source_name.c_str(); } + + /** + * Returns the instance of the TUIO source + */ + unsigned int getSourceInstance() { return source_instance; } + + /** + * Returns the address of the TUIO source + */ + const char* getSourceAddress() { return source_address.c_str(); } + + /** + * Encodes the sensor dimension + * @param w the sensor width + * @param h the sensor height + */ + void setDimension(unsigned short w, unsigned short h) { + dimension = w << 16 | h; + } + + /** + * Sets the encoded sensor dimension + * @param d the sensor dimension + */ + void setDimension(unsigned int d) { + dimension = d; + } + + /** + * Returns the encoded sensor dimension + * @return the encoded sensor dimension + */ + unsigned int getDimension() { + return dimension; + } + + /** + * Returns the decoded sensor width + * @return the decoded sensor width + */ + unsigned short getWidth() { + unsigned short width = dimension >> 16; + return width; + } + + /** + * Returns the decoded sensor height + * @return the decoded sensor height + */ + unsigned short getHeight() { + unsigned short height = dimension & 0x0000FFFF; + return height; + } + + /** + * Sets the last frame time + * @param ttime the TuioTime of the last frame + */ + void setFrameTime(TuioTime ttime) { + frameTime = ttime; + } + + /** + * Returns the last frame time + * @return the TuioTime of the last frame + */ + TuioTime getFrameTime() { + return frameTime; + } + }; +} +#endif // INCLUDED_TUIOSOURCE_H diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp new file mode 100644 index 0000000000..4447c3a227 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp @@ -0,0 +1,91 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioSymbol.h" + +using namespace TUIO2; + +TuioSymbol::TuioSymbol (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data):TuioComponent(ttime,tobj,0,0,0) { + currentTime = ttime; + startTime = currentTime; + type_id = ti; + user_id = ui; + symbol_id = sym; + symbol_type = std::string(type); + symbol_data = std::string(data); + state = TUIO_ADDED; +} + +TuioSymbol::TuioSymbol (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data):TuioComponent(tobj,0,0,0) { + currentTime = TuioTime::getSystemTime(); + startTime = currentTime; + type_id = ti; + user_id = ui; + symbol_id = sym; + symbol_type = std::string(type); + symbol_data = std::string(data); + state = TUIO_ADDED; +} + +TuioSymbol::TuioSymbol (TuioSymbol *tsym):TuioComponent(tsym->getTuioTime(),tsym->getContainingTuioObject(),0,0,0) { + currentTime = TuioTime::getSystemTime(); + startTime = currentTime; + session_id = tsym->getSessionID(); + type_id = tsym->getTypeID(); + user_id = tsym->getUserID(); + symbol_id = tsym->getSymbolID(); + symbol_type = tsym->getSymbolType(); + symbol_data = tsym->getSymbolData(); + state = TUIO_ADDED; +} + +unsigned int TuioSymbol::getSymbolID() const { + return symbol_id; +} + +unsigned short TuioSymbol::getTypeID() const { + return type_id; +} + +unsigned short TuioSymbol::getUserID() const { + return user_id; +} + +unsigned int TuioSymbol::getTypeUserID() const { + int tu_id = user_id << 16 | type_id; + return tu_id; +} + +void TuioSymbol::setTypeUserID(unsigned int tu_id) { + user_id = tu_id >> 16; + type_id = tu_id & 0x0000FFFF; +} + +const char* TuioSymbol::getSymbolType() const { + return symbol_type.c_str(); +} + +const char* TuioSymbol::getSymbolData() const { + return symbol_data.c_str(); +} + +void TuioSymbol::update(TuioTime ttime) { + TuioComponent::update(ttime,0,0); + +} + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h b/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h new file mode 100644 index 0000000000..d66e32845d --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h @@ -0,0 +1,160 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOSYMBOL_H +#define INCLUDED_TUIOSYMBOL_H +//#pragma clang diagnostic ignored "-Woverloaded-virtual" + +#include "TuioTime.h" +#include "TuioComponent.h" +#include + +namespace TUIO2 { + + /** + * The TuioSymbol class encapsulates /tuio2/sym TUIO symbol. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioSymbol : public TuioComponent { + + protected: + /** + * The unique Session ID that is assigned to each TUIO tobj. + */ + unsigned int session_id; + /** + * The individual symbol ID number that is assigned to each TuioToken. + */ + unsigned int symbol_id; + /** + * The symbol type ID that is assigned to each TuioToken. + */ + unsigned short type_id; + /** + * The user ID that is assigned to each TuioToken. + */ + unsigned short user_id; + /** + * The symbol type descriptor + */ + std::string symbol_type; + /** + * The actual symbol data + */ + std::string symbol_data; + /** + * The time stamp of the last update represented as TuioTime (time since session start) + */ + TuioTime currentTime; + /** + * The creation time of this TuioPoint represented as TuioTime (time since session start) + */ + TuioTime startTime; + /** + * Reflects the current state of the TuioSymbol + */ + unsigned char state; + + public: + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, Type ID, User ID and Symbol ID as well as the Symbol type and data. + * + * @param ttime the TuioTime to assign + * @param tobj the TuioObject to assign + * @param ti the Type ID to assign + * @param ui the User ID to assign + * @param sym the Symbol ID to assign + * @param type the symbol type descriptor + * @param data the symbol data to assign + */ + TuioSymbol (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data); + + /** + * This constructor assigns the provided Session ID, Type ID, User ID and Symbol ID + * as well as the Symbol type and data. + * + * @param tobj the TuioObject to assign + * @param ti the Type ID to assign + * @param ui the User ID to assign + * @param sym the Symbol ID to assign + * @param type the symbol type descriptor + * @param data the symbol data to assign + */ + TuioSymbol (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data); + + /** + * This constructor takes a TuioSymbol argument and sets its attributes + * to the ones of the provided TuioSymbol. + * + * @param tsym the TuioSymbol to assign + */ + TuioSymbol (TuioSymbol *tsym); + + /** + * Returns the Symbol ID of this TuioSymbol. + * @return the Symbol ID of this TuioSymbol + */ + unsigned int getSymbolID() const; + + /** + * Returns the Type ID of this TuioSymbol. + * @return the Type ID of this TuioSymbol + */ + unsigned short getTypeID() const; + + /** + * Returns the User ID of this TuioSymbol. + * @return the User ID of this TuioSymbol + */ + unsigned short getUserID() const; + + /** + * Returns the encoded Type & User ID of this TuioSymbol. + * @return the encoded Type & User ID of this TuioSymbol + */ + unsigned int getTypeUserID() const; + + /** + * Decodes and assigns the Type & User ID to this TuioSymbol. + * @param tu_id the encoded Type & User ID of this TuioSymbol + */ + void setTypeUserID(unsigned int tu_id); + + /** + * Returns the Type string of this TuioSymbol. + * @return the Type string of this TuioSymbol + */ + const char* getSymbolType() const; + + /** + * Returns the actual data of this TuioSymbol. + * @return the actual data of this TuioSymbol + */ + const char* getSymbolData() const; + + + void update(TuioTime ttime); + /*void update(TuioTime ttime, float xp, float yp); + void update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma); + void update (TuioSymbol *tsym);*/ + }; +} +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp new file mode 100644 index 0000000000..b84af84458 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp @@ -0,0 +1,160 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioTime.h" +using namespace TUIO2; + +long TuioTime::start_seconds = 0; +long TuioTime::start_micro_seconds = 0; + +TuioTime::TuioTime (long msec) { + seconds = msec/MSEC_SECOND; + micro_seconds = USEC_MILLISECOND*(msec%MSEC_SECOND); +} + +TuioTime::TuioTime (osc::TimeTag timetag) { + osc::uint32 secs = timetag >> 32; + osc::uint32 frac = timetag & 0x00000000FFFFFFFF; + + seconds = secs - JAN_1970; + micro_seconds = frac / NTP_UNITS; +} + +TuioTime::TuioTime (long sec, long usec) { + seconds = sec; + micro_seconds = usec; +} + +TuioTime TuioTime::operator+(long us) { + long sec = seconds + us/USEC_SECOND; + long usec = micro_seconds + us%USEC_SECOND; + return TuioTime(sec,usec); +} + +TuioTime TuioTime::operator+(TuioTime ttime) { + long sec = seconds + ttime.getSeconds(); + long usec = micro_seconds + ttime.getMicroseconds(); + sec += usec/USEC_SECOND; + usec = usec%USEC_SECOND; + return TuioTime(sec,usec); +} + +TuioTime TuioTime::operator-(long us) { + long sec = seconds - us/USEC_SECOND; + long usec = micro_seconds - us%USEC_SECOND; + + if (usec<0) { + usec += USEC_SECOND; + sec--; + } + + return TuioTime(sec,usec); +} + +TuioTime TuioTime::operator-(TuioTime ttime) { + long sec = seconds - ttime.getSeconds(); + long usec = micro_seconds - ttime.getMicroseconds(); + + if (usec<0) { + usec += USEC_SECOND; + sec--; + } + + return TuioTime(sec,usec); +} + +void TuioTime::operator=(TuioTime ttime) { + seconds = ttime.getSeconds(); + micro_seconds = ttime.getMicroseconds(); +} + +bool TuioTime::operator==(TuioTime ttime) { + if ((seconds==(long)ttime.getSeconds()) && (micro_seconds==(long)ttime.getMicroseconds())) return true; + else return false; +} + +bool TuioTime::operator!=(TuioTime ttime) { + if ((seconds!=(long)ttime.getSeconds()) || (micro_seconds!=(long)ttime.getMicroseconds())) return true; + else return false; +} + +void TuioTime::reset() { + seconds = 0; + micro_seconds = 0; + + TuioTime system_time = getSystemTime(); + seconds = system_time.getSeconds(); + micro_seconds = system_time.getMicroseconds(); +} + +long TuioTime::getSeconds() const{ + return seconds; +} + +long TuioTime::getMicroseconds() const{ + return micro_seconds; +} + +long TuioTime::getTotalMilliseconds() const{ + return seconds*MSEC_SECOND+micro_seconds/MSEC_SECOND; +} + +unsigned int TuioTime::getFrameID() const{ + return frame_id; +} + +void TuioTime::setFrameID(unsigned int f_id) { + frame_id = f_id; +} + +/*void TuioTime::initSession() { + TuioTime startTime = TuioTime::getSystemTime(); + start_seconds = startTime.getSeconds(); + start_micro_seconds = startTime.getMicroseconds(); +} + +TuioTime TuioTime::getSessionTime() { + return (getSystemTime() - getStartTime()); +}*/ + +TuioTime TuioTime::getStartTime() { + return TuioTime(start_seconds,start_micro_seconds); +} + +TuioTime TuioTime::getSystemTime() { +#ifdef WIN32 + TuioTime systemTime(GetTickCount()); +#else + struct timeval tv; + struct timezone tz; + gettimeofday(&tv,&tz); + TuioTime systemTime(tv.tv_sec,tv.tv_usec); +#endif + return systemTime; +} + +osc::TimeTag TuioTime::getSystemTimeTag() { + + TuioTime systemTime = getSystemTime(); + + osc::uint32 secs = systemTime.getSeconds() + JAN_1970; + osc::uint32 frac = systemTime.getMicroseconds() * NTP_UNITS; + + osc::uint64 timetag = (osc::uint64) secs << 32 | frac; + return osc::TimeTag(timetag); +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioTime.h b/modules/touch/ext/libTUIO2/TUIO2/TuioTime.h new file mode 100644 index 0000000000..f1c1e10133 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioTime.h @@ -0,0 +1,222 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOTIME_H +#define INCLUDED_TUIOTIME_H + +#include "LibExport.h" +#include "oscpack/osc/OscTypes.h" + +#ifndef WIN32 +#include +#include +#else +#include +#include +#endif + +#define MSEC_SECOND 1000 +#define USEC_SECOND 1000000 +#define USEC_MILLISECOND 1000 + +#define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */ +#define NTP_UNITS 4294.967295 /* NTP units per second */ + +namespace TUIO2 { + + /** + * The TuioTime class is a simple structure that is used to reprent the time that has elapsed since the session start. + * The time is internally represented as seconds and fractions of microseconds which should be more than sufficient for gesture related timing requirements. + * Therefore at the beginning of a typical TUIO session the static method initSession() will set the reference time for the session. + * Another important static method getSessionTime will return a TuioTime object representing the time elapsed since the session start. + * The class also provides various addtional convience method, which allow some simple time arithmetics. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioTime { + + private: + long seconds; + long micro_seconds; + static long start_seconds; + static long start_micro_seconds; + + unsigned int frame_id; + + public: + + /** + * The default constructor takes no arguments and sets + * the Seconds and Microseconds attributes of the newly created TuioTime both to zero. + */ + TuioTime ():seconds(0),micro_seconds(0),frame_id(0) {}; + + /** + * The destructor is doing nothing in particular. + */ + ~TuioTime() {} + + /** + * This constructor takes the provided time represented in total Milliseconds + * and assigs this value to the newly created TuioTime. + * + * @param msec the total time in Millseconds + */ + TuioTime (long msec); + + + /** + * This constructor takes the provided time in OSC format + * and assigs this value to the newly created TuioTime. + * + * @param tag the time in OSC format + */ + TuioTime (osc::TimeTag timetag); + + /** + * This constructor takes the provided time represented in Seconds and Microseconds + * and assigs these value to the newly created TuioTime. + * + * @param sec the total time in seconds + * @param usec the microseconds time component + */ + TuioTime (long sec, long usec); + + /** + * Sums the provided time value represented in total Microseconds to this TuioTime. + * + * @param us the total time to add in Microseconds + * @return the sum of this TuioTime with the provided argument in microseconds + */ + TuioTime operator+(long us); + + /** + * Sums the provided TuioTime to the private Seconds and Microseconds attributes. + * + * @param ttime the TuioTime to add + * @return the sum of this TuioTime with the provided TuioTime argument + */ + TuioTime operator+(TuioTime ttime); + + /** + * Subtracts the provided time represented in Microseconds from the private Seconds and Microseconds attributes. + * + * @param us the total time to subtract in Microseconds + * @return the subtraction result of this TuioTime minus the provided time in Microseconds + */ + TuioTime operator-(long us); + + /** + * Subtracts the provided TuioTime from the private Seconds and Microseconds attributes. + * + * @param ttime the TuioTime to subtract + * @return the subtraction result of this TuioTime minus the provided TuioTime + */ + TuioTime operator-(TuioTime ttime); + + + /** + * Assigns the provided TuioTime to the private Seconds and Microseconds attributes. + * + * @param ttime the TuioTime to assign + */ + void operator=(TuioTime ttime); + + /** + * Takes a TuioTime argument and compares the provided TuioTime to the private Seconds and Microseconds attributes. + * + * @param ttime the TuioTime to compare + * @return true if the two TuioTime have equal Seconds and Microseconds attributes + */ + bool operator==(TuioTime ttime); + + /** + * Takes a TuioTime argument and compares the provided TuioTime to the private Seconds and Microseconds attributes. + * + * @param ttime the TuioTime to compare + * @return true if the two TuioTime have differnt Seconds or Microseconds attributes + */ + bool operator!=(TuioTime ttime); + + /** + * Resets the seconds and micro_seconds attributes to zero. + */ + void reset(); + + /** + * Returns the TuioTime Seconds component. + * @return the TuioTime Seconds component + */ + long getSeconds() const; + + /** + * Returns the TuioTime Microseconds component. + * @return the TuioTime Microseconds component + */ + long getMicroseconds() const; + + /** + * Returns the total TuioTime in Milliseconds. + * @return the total TuioTime in Milliseconds + */ + long getTotalMilliseconds() const; + + /** + * Returns the assigned Frame ID. + * @return the assigned Frame ID + */ + unsigned int getFrameID() const; + + /** + * assigns a Frame ID. + * @f_id the Frame ID to assign + */ + void setFrameID(unsigned int f_id); + + /** + * This static method globally resets the TUIO session time. + */ + //static void initSession(); + + /** + * Returns the present TuioTime representing the time since session start. + * @return the present TuioTime representing the time since session start + */ + //tatic TuioTime getSessionTime(); + + /** + * Returns the absolut TuioTime representing the session start. + * @return the absolut TuioTime representing the session start + */ + static TuioTime getStartTime(); + + /** + * Returns the absolut TuioTime representing the current system time. + * @return the absolut TuioTime representing the current system time + */ + static TuioTime getSystemTime(); + + /** + * Returns the absolut TuioTime representing the current system time. + * @return the absolut TuioTime representing the current system time + */ + static osc::TimeTag getSystemTimeTag(); + }; +} +#endif /* INCLUDED_TUIOTIME_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp new file mode 100644 index 0000000000..375c80e792 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp @@ -0,0 +1,69 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioToken.h" + +using namespace TUIO2; + +TuioToken::TuioToken (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a):TuioComponent(ttime, tobj, xp, yp,a) { + type_id = ti; + user_id = ui; + symbol_id = sym; +} + +TuioToken::TuioToken (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a):TuioComponent(tobj, xp, yp, a) { + type_id = ti; + user_id = ui; + symbol_id = sym; +} + +TuioToken::TuioToken (TuioObject *tobj, unsigned int sym, float xp, float yp, float a):TuioComponent(tobj, xp, yp, a) { + type_id = 0; + user_id = 0; + symbol_id = sym; +} + +TuioToken::TuioToken (TuioToken *ttok):TuioComponent(ttok) { + symbol_id = ttok->getSymbolID(); +} + +void TuioToken::stop (TuioTime ttime) { + update(ttime,xpos,ypos,angle); +} + +unsigned int TuioToken::getSymbolID() const{ + return symbol_id; +} + +unsigned short TuioToken::getTypeID() const{ + return type_id; +}; + +unsigned short TuioToken::getUserID() const{ + return user_id; +}; + +unsigned int TuioToken::getTypeUserID() const { + int tu_id = user_id << 16 | type_id; + return tu_id; +} + +void TuioToken::setTypeUserID(unsigned int tu_id) { + user_id = tu_id >> 16; + type_id = tu_id & 0x0000FFFF; +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioToken.h b/modules/touch/ext/libTUIO2/TUIO2/TuioToken.h new file mode 100644 index 0000000000..c6b01a0816 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioToken.h @@ -0,0 +1,151 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOTOKEN_H +#define INCLUDED_TUIOTOKEN_H + +#include "TuioComponent.h" + +namespace TUIO2 { + + /** + * The TuioToken class encapsulates /tuio2/tok TUIO tokens. + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL TuioToken: public TuioComponent { + + protected: + /** + * The individual symbol ID number that is assigned to each TuioToken. + */ + unsigned int symbol_id; + /** + * The symbol type ID that is assigned to each TuioToken. + */ + unsigned short type_id; + /** + * The user ID that is assigned to each TuioToken. + */ + unsigned short user_id; + + public: + using TuioComponent::update; + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, Symbol ID, X and Y coordinate and angle to the newly created TuioToken. + * + * @param ttime the TuioTime to assign + * @param tobj the TuioObject to assign + * @param ti the Type ID to assign + * @param ui the User ID to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + TuioToken (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a); + + /** + * This constructor takes the provided Session ID, Symbol ID, X and Y coordinate + * and angle, and assigs these values to the newly created TuioToken. + * + * @param tobj the TuioObject to assign + * @param ti the Type ID to assign + * @param ui the User ID to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + TuioToken (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a); + + /** + * This constructor takes the provided Session ID, Symbol ID, X and Y coordinate + * and angle, and assigs these values to the newly created TuioToken. + * + * @param tobj the TuioObject to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + TuioToken (TuioObject *tobj, unsigned int sym, float xp, float yp, float a); + + /** + * This constructor takes the atttibutes of the provided TuioToken + * and assigs these values to the newly created TuioToken. + * + * @param ttok the TuioToken to assign + */ + TuioToken (TuioToken *ttok); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioToken() {}; + + /** + * This method is used to calculate the speed and acceleration values of a + * TuioToken with unchanged position and angle. + */ + void stop (TuioTime ttime); + + /** + * Takes the atttibutes of the provided TuioToken + * and assigs these values to this TuioToken. + * The TuioTime time stamp of this TuioToken remains unchanged. + * + * @param ttok the TuioToken to assign + */ + void update (TuioToken *ttok); + + /** + * Returns the symbol ID of this TuioToken. + * @return the symbol ID of this TuioToken + */ + unsigned int getSymbolID() const; + + /** + * Returns the Type ID of this TuioToken. + * @return the Type ID of this TuioToken + */ + unsigned short getTypeID() const; + + /** + * Returns the User ID of this TuioToken. + * @return the User ID of this TuioToken + */ + unsigned short getUserID() const; + + /** + * Returns the encoded Type & User ID of this TuioToken. + * @return the encoded Type & User ID of this TuioToken + */ + unsigned int getTypeUserID() const; + + /** + * Decodes and assigns the Type & User ID to this TuioToken. + * @param tu_id the encoded Type & User ID of this TuioToken + */ + void setTypeUserID(unsigned int tu_id); + }; +} +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp b/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp new file mode 100644 index 0000000000..fe1b3ad952 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp @@ -0,0 +1,92 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "UdpReceiver.h" + +using namespace TUIO2; +using namespace osc; + +#ifndef WIN32 +static void* ClientThreadFunc( void* obj ) +#else +static DWORD WINAPI ClientThreadFunc( LPVOID obj ) +#endif +{ + static_cast(obj)->socket->Run(); + return 0; +}; + +UdpReceiver::UdpReceiver(unsigned short port):locked (false) { + try { + socket = new UdpListeningReceiveSocket(IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), this ); + } catch (std::exception &e) { + std::cerr << "could not bind to UDP port " << port << std::endl; + socket = NULL; + } + + if (socket!=NULL) { + if (!socket->IsBound()) { + delete socket; + socket = NULL; + } else std::cout << "listening to TUIO/UDP messages on port " << port << std::endl; + } +} + +UdpReceiver::~UdpReceiver() { + delete socket; +} + +void UdpReceiver::connect(bool lk) { + + if (connected) return; + if (socket==NULL) return; + locked = lk; + + if (!locked) { +#ifndef WIN32 + pthread_create(&thread , NULL, ClientThreadFunc, this); +#else + DWORD threadId; + thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &threadId ); +#endif + } else socket->Run(); + + connected = true; +} + +void UdpReceiver::disconnect() { + + if (!connected) return; + if (socket==NULL) { + connected = false; + locked = false; + return; + } + socket->Break(); + + if (!locked) { +#ifdef WIN32 + if( thread ) CloseHandle( thread ); +#endif + thread = 0; + } else locked = false; + + connected = false; +} + + diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.h b/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.h new file mode 100644 index 0000000000..026e09ae26 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.h @@ -0,0 +1,77 @@ +/* + TUIO2 C++ Library + Copyright (c) 2009-2014 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_UDPRECEIVER_H +#define INCLUDED_UDPRECEIVER_H + +#include "OscReceiver.h" +#include "oscpack/ip/UdpSocket.h" + +namespace TUIO2 { + + /** + * The UdpReceiver provides the OscReceiver functionality for the UDP transport method + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL UdpReceiver: public OscReceiver { + + public: + + /** + * The UDP socket is only public to be accessible from the thread function + */ + UdpListeningReceiveSocket *socket; + + /** + * This constructor creates a UdpReceiver instance listening to the provided UDP port + * + * @param port the number of the UDP port to listen to, defaults to 3333 + */ + UdpReceiver (unsigned short port=3333); + + /** + * The destructor is doing nothing in particular. + */ + virtual ~UdpReceiver(); + + /** + * The UdpReceiver connects and starts receiving TUIO messages via UDP + * + * @param lock running in the background if set to false (default) + */ + void connect(bool lock=false); + + /** + * The UdpReceiver disconnects and stops receiving TUIO messages via UDP + */ + void disconnect(); + + private: + +#ifndef WIN32 + pthread_t thread; +#else + HANDLE thread; +#endif + + bool locked; + }; +}; +#endif /* INCLUDED_UDPRECEIVER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpSender.cpp b/modules/touch/ext/libTUIO2/TUIO2/UdpSender.cpp new file mode 100644 index 0000000000..9a231a5617 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/UdpSender.cpp @@ -0,0 +1,89 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "UdpSender.h" + +using namespace TUIO2; + +UdpSender::UdpSender() { + try { + local = true; + long unsigned int ip = GetHostByName("localhost"); + socket = new UdpTransmitSocket(IpEndpointName(ip, 3333)); + buffer_size = MAX_UDP_SIZE; + std::cout << "TUIO/UDP messages to " << "127.0.0.1@3333" << std::endl; + } catch (std::exception &e) { + std::cout << "could not create UDP socket" << std::endl; + socket = NULL; + throw std::exception(); + } +} + +UdpSender::UdpSender(const char *host, int port) { + try { + if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) { + local = true; + buffer_size = MAX_UDP_SIZE; + } else { + local = false; + buffer_size = IP_MTU_SIZE; + } + long unsigned int ip = GetHostByName(host); + socket = new UdpTransmitSocket(IpEndpointName(ip, port)); + std::cout << "TUIO/UDP messages to " << host << "@" << port << std::endl; + } catch (std::exception &e) { + std::cout << "could not create UDP socket" << std::endl; + socket = NULL; + throw std::exception(); + } +} + +UdpSender::UdpSender(const char *host, int port, int size) { + try { + if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) { + local = true; + } else local = false; + long unsigned int ip = GetHostByName(host); + socket = new UdpTransmitSocket(IpEndpointName(ip, port)); + if (buffer_size>MAX_UDP_SIZE) buffer_size = MAX_UDP_SIZE; + else if (buffer_sizeSize() > buffer_size ) return false; + if ( bundle->Size() == 0 ) return false; + + socket->Send( bundle->Data(), bundle->Size() ); + return true; +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpSender.h b/modules/touch/ext/libTUIO2/TUIO2/UdpSender.h new file mode 100644 index 0000000000..9cd2eb722f --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/UdpSender.h @@ -0,0 +1,93 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_UDPSENDER_H +#define INCLUDED_UDPSENDER_H + +#include "OscSender.h" +#include "oscpack/ip/UdpSocket.h" + +#define IP_MTU_SIZE 1500 +#define MAX_UDP_SIZE 4096 +#define MIN_UDP_SIZE 576 + +namespace TUIO2 { + + /** + * The UdpSender implements the UDP transport method for OSC + * + * @author Martin Kaltenbrunner + * @version 2.0.a0 + */ + class LIBDECL UdpSender : public OscSender { + + public: + + /** + * The default constructor creates a UdpSender that sends to the default UDP port 3333 on localhost + * using the maximum packet size of 65536 bytes for single packets on the loopback device + */ + UdpSender(); + + /** + * This constructor creates a UdpSender that sends to the provided port on the the given host + * using the default MTU size of 1500 bytes to deliver unfragmented UDP packets on a LAN + * + * @param host the receiving host name + * @param port the outgoing UDP port number + */ + + UdpSender(const char *host, int port); + /** + * This constructor creates a UdpSender that sends to the provided port on the the given host + * the UDP packet size can be set to a value between 576 and 65536 bytes + * + * @param host the receiving host name + * @param port the outgoing UDP port number + * @param size the maximum UDP packet size + */ + UdpSender(const char *host, int port, int size); + + /** + * The destructor closes the socket. + */ + virtual ~UdpSender(); + + /** + * This method delivers the provided OSC data + * + * @param *bundle the OSC stream to deliver + * @return true if the data was delivered successfully + */ + + bool sendOscPacket (osc::OutboundPacketStream *bundle); + + /** + * This method returns the connection state + * + * @return true if the connection is alive + */ + bool isConnected (); + + const char* tuio_type() { return "TUIO/UDP"; } + + private: + UdpTransmitSocket *socket; + }; +} +#endif /* INCLUDED_UDPSENDER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.cpp b/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.cpp new file mode 100644 index 0000000000..781fcb5e75 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.cpp @@ -0,0 +1,286 @@ +/* + TUIO C++ Library + Copyright (c) 2009-2016 Martin Kaltenbrunner + WebSockSender (c) 2015 Florian Echtler + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "WebSockSender.h" + +#ifdef WIN32 +#if not + defined int32_t + typedef DWORD int32_t; +#endif +#endif + +using namespace TUIO2; + +WebSockSender::WebSockSender() + :TcpSender( 8080 ) +{ + local = true; + buffer_size = MAX_TCP_SIZE; + port_no = 8080; +} + +WebSockSender::WebSockSender(int port) + :TcpSender( port ) +{ + local = true; + buffer_size = MAX_TCP_SIZE; + port_no = port; +} + +bool WebSockSender::sendOscPacket (osc::OutboundPacketStream *bundle) { + if (!connected) return false; + if ( bundle->Size() > buffer_size ) return false; + if ( bundle->Size() == 0 ) return false; + +#ifdef OSC_HOST_LITTLE_ENDIAN + data_size[0] = bundle->Size()>>24; + data_size[1] = (bundle->Size()>>16) & 255; + data_size[2] = (bundle->Size()>>8) & 255; + data_size[3] = (bundle->Size()) & 255; +#else + *((int32_t*)data_size) = bundle->Size(); +#endif + +#ifdef WIN32 + std::list::iterator client; +#else + std::list::iterator client; +#endif + + for (client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) { + int len = bundle->Size(); + // add WebSocket header on top + uint8_t header[4] = { + 0x82, + (uint8_t)( len & 0xFF), + (uint8_t)((len >>8) & 0xFF), + (uint8_t)( len & 0xFF) + }; + int hs = 2; + if (len > 125) { hs = 4; header[1] = 126; } + memcpy(&data_buffer[0], &header, hs); + memcpy(&data_buffer[hs], bundle->Data(), bundle->Size()); + send((*client),data_buffer, hs+bundle->Size(),0); + } + + return true; +} + +void WebSockSender::newClient( int tcp_client ) { + + // socket -> file descriptor +#ifdef WIN32 + FILE* conn = _fdopen( tcp_client, "r+" ); +#else + FILE* conn = fdopen( tcp_client, "r+" ); +#endif + + // websocket challenge-response + uint8_t digest[SHA1_HASH_SIZE]; + char buf[1024] = "..."; + char key[1024]; + + // read client handshake challenge + while ((buf[0] != 0) && (buf[0] != '\r')) { + fgets( buf, sizeof(buf), conn ); + if (strncmp(buf,"Sec-WebSocket-Key: ",19) == 0) { + strncpy(key,buf+19,sizeof(key)); + key[strlen(buf)-21] = 0; + break; + } + } + + strncat(key,"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",sizeof(key)-strlen(key)-1); + sha1(digest,(uint8_t*)key,strlen(key)); + + snprintf(buf, sizeof(buf), + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: %s\r\n\r\n", + base64( digest, SHA1_HASH_SIZE ).c_str() ); + + send(tcp_client,buf, strlen(buf),0); +} + + +/* + * Incredibly minimal implementation of SHA1. + * Totally independent of any other code (even libc) so it can be + * run on bare hardware. + * + * Copyright (C) 2009 John Stumpo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JOHN STUMPO ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL JOHN STUMPO BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +void WebSockSender::sha1( uint8_t digest[SHA1_HASH_SIZE], const uint8_t* inbuf, size_t length) { + + size_t i, j; + int remaining_bytes; + uint32_t h0, h1, h2, h3, h4, a, b, c, d, e, temp; + uint32_t w[80]; + unsigned char buf[64]; + + /* Initialize SHA1 hash state. */ + h0 = 0x67452301; + h1 = 0xefcdab89; + h2 = 0x98badcfe; + h3 = 0x10325476; + h4 = 0xc3d2e1f0; + + /* The extra 9 bytes are the pad byte (0x80) and 64-bit bit count that + are appended to the data being hashed. (There will more than likely + also be some zeroes in between the 0x80 and the bit count so that we + operate on a multiple of 64 bytes; 9 bytes, though, is the minimal + amount of extra data.) */ + for (i = 0; i < length + 9; i += 64) { + + /* Perform any padding necessary. */ + remaining_bytes = length - i; + if (remaining_bytes >= 64) { + memcpy(buf, inbuf + i, 64); + } else if (remaining_bytes >= 0) { + memcpy(buf, inbuf + i, remaining_bytes); + memset(buf + remaining_bytes, 0, 64 - remaining_bytes); + buf[remaining_bytes] = 0x80; + } else { + memset(buf, 0, 64); + } + + if (remaining_bytes < 56) + *(uint32_t*)(buf + 60) = SWAP(length * 8); + + /* Build the input array. */ + for (j = 0; j < 16; j++) + w[j] = SWAP(*(uint32_t*)(buf + j * 4)); + + for (j = 16; j < 80; j++) + w[j] = ROL(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); + + /* Load hash state. */ + a = h0; + b = h1; + c = h2; + d = h3; + e = h4; + + for (j = 0; j < 80; j++) { + + if (j < 20) + temp = ((b & c) | ((~b) & d)) + 0x5a827999; + else if (j < 40) + temp = (b ^ c ^ d) + 0x6ed9eba1; + else if (j < 60) + temp = ((b & c) | (b & d) | (c & d)) + 0x8f1bbcdc; + else + temp = (b ^ c ^ d) + 0xca62c1d6; + + temp += ROL(a, 5) + e + w[j]; + + e = d; + d = c; + c = ROR(b, 2); + b = a; + a = temp; + } + + /* Incorporate the results of the hash operation. */ + h0 += a; + h1 += b; + h2 += c; + h3 += d; + h4 += e; + } + + /* Write the hash into the output buffer. */ + *(uint32_t*)(digest) = SWAP(h0); + *(uint32_t*)(digest + 4) = SWAP(h1); + *(uint32_t*)(digest + 8) = SWAP(h2); + *(uint32_t*)(digest + 12) = SWAP(h3); + *(uint32_t*)(digest + 16) = SWAP(h4); +} + +/* + * a very simple base64 encoder, licensed as public domain. original source: + * https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64 + */ + +const static unsigned char encodeLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const static unsigned char padCharacter = '='; + +std::string WebSockSender::base64( uint8_t* cursor, size_t size ) { + + std::string encodedString; + uint32_t temp; + + encodedString.reserve(((size/3) + (size % 3 > 0)) * 4); + + for (size_t idx = 0; idx < size/3; idx++) { + + temp = (*cursor++) << 16; + temp += (*cursor++) << 8; + temp += (*cursor++); + + encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] ); + encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] ); + encodedString.append( 1, encodeLookup[(temp & 0x00000FC0) >> 6 ] ); + encodedString.append( 1, encodeLookup[(temp & 0x0000003F) ] ); + } + + switch (size % 3) { + case 1: + temp = (*cursor++) << 16; + encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] ); + encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] ); + encodedString.append( 2, padCharacter ); + break; + case 2: + temp = (*cursor++) << 16; + temp += (*cursor++) << 8; + encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] ); + encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] ); + encodedString.append( 1, encodeLookup[(temp & 0x00000FC0) >> 6 ] ); + encodedString.append( 1, padCharacter); + break; + } + + return encodedString; +} + + diff --git a/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.h b/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.h new file mode 100644 index 0000000000..0cc9d12935 --- /dev/null +++ b/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.h @@ -0,0 +1,121 @@ +/* + TUIO C++ Library + Copyright (c) 2009-2016 Martin Kaltenbrunner + WebSockSender (c) 2015 Florian Echtler + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_WEBSOCKSENDER_H +#define INCLUDED_WEBSOCKSENDER_H + +#if defined(_MSC_VER) && _MSC_VER < 1900 +#include +#include +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} + +#endif + + +/* All of these macros assume use on a 32-bit variable. + Additionally, SWAP assumes we're little-endian. */ +#define SWAP(a) ((((a) >> 24) & 0x000000ff) | (((a) >> 8) & 0x0000ff00) | \ +(((a) << 8) & 0x00ff0000) | (((a) << 24) & 0xff000000)) +#define ROL(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) +#define ROR(a, b) ROL((a), (32 - (b))) +#define SHA1_HASH_SIZE (160/8) + +#include "TcpSender.h" +#include +#include +#include +#include + +namespace TUIO2 { + + /** + * The WebSockSender implements the WebSocket transport method for OSC + * + * @author Florian Echtler + * @version 2.0.a0 + */ + class LIBDECL WebSockSender : public TcpSender { + + public: + + /** + * The default constructor creates a WebSockSender that listens to the default HTTP-alt port 8080 on localhost + */ + WebSockSender(); + + /** + * This constructor creates a WebSockSender that listens to the provided port + * + * @param port the listening WebSocket port number + */ + WebSockSender(int port); + + /** + * The destructor closes the socket. + */ + virtual ~WebSockSender() {} + + /** + * This method delivers the provided OSC data + * + * @param *bundle the OSC stream to deliver + * @return true if the data was delivered successfully + */ + bool sendOscPacket (osc::OutboundPacketStream *bundle); + + /** + * This method is called whenever a new client connects + * + * @param tcp_client the socket handle of the new client + */ + void newClient( int tcp_client ); + + const char* tuio_type() { return "TUIO/WEB"; } + private: + + void sha1( uint8_t digest[SHA1_HASH_SIZE], const uint8_t* inbuf, size_t length ); + std::string base64( uint8_t* buffer, size_t size ); + }; +} +#endif /* INCLUDED_WEBSOCKSENDER_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/CHANGES b/modules/touch/ext/libTUIO2/oscpack/CHANGES new file mode 100644 index 0000000000..5db666be36 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/CHANGES @@ -0,0 +1,159 @@ +April 9, 2013 +------------- + +Changes for the 1.1.0 release (vs 1.0.2) are listed below. Unless +otherwise indicated these changes have been made since +January 2013. The focus has been on general clean-up, fixing bugs, +compiler errors and warnings, and fixing issues on 64 bit platforms. +A few improvements such as support for OSC arrays, functions +for setting broadcast and reuse socket options have been added. +This update merges changes from the openFrameworks version +of oscpack. + + - Added support for arrays in messages (see OscUnitTests.cpp + for example usage). (patch thanks to Tim Blechmann) + + - Fixed bugs relating to 64 bit usage (e.g. crashes in 64 bit + builds on OS X). + + - Some member functions that previously used the "int" or + "unsigned long" type for parameters or return values now use + std::size_t (platform-defined) or + osc_bundle_element_size_t (a.k.a. int32). + This change was made to better support 64 bit platforms. + See SVN revision 70 for details. + + - The previous point introduces a breaking change on Linux/x86_64 + for callers of AsBlob() and AsBlobUnchecked(): + The type of the second argument (the "size" argument) to + ReceivedMessageArgument::AsBlob() and + ReceivedMessageArgument::AsBlobUnchecked() has changed + from unsigned long & to osc_bundle_element_size_t (an int32). + You should declare your size argument variables as + osc_bundle_element_size_t to avoid incompatibilities between + 32 and 64 bit builds. + + - Note that oscpack does not support packets larger than + 0x7FFFFFFC (see comments in class ReceivedPacket for + details). + + - Oscpack defines an osc::Nil value used for sending the nil + message argument value. This conflicts with Objective-C. + Therefore osc::Nil is no longer defined in Obj-C++ code. + There is now an osc::OscNil value, which should be preferred. + osc::Nil is still available when writing C++. + (fix thanks to openFrameworks) + + - Added UdpSocket::SetEnableBroadcast(). This needs to + be called to enable sending to the broadcast address on some + platforms (e.g. Mac OS X). (thanks to openFrameworks) + + - Added UdpSocket::SetAllowReuse(). This is useful for + sharing sockets on some platforms (Mac?), and not so useful + on other platforms. (thanks to openFrameworks) + + - Added IpEndpointName::IsMulticastAddress() (2010) + + - Cleaned up C++ header usage and std:: namespace usage + to be more standards compliant (fixes issues on recent compilers + such as clang and gcc4.6). + + - Improved host endianness detection. Should auto-detect + endianness on most platforms now. + (thanks to Tim Blechmann for help with this) + + - Fixed two memory leaks: (1) in OscPrintReceivedElements.cpp + when printing time tag message arguments (thanks to Gwydion ap Dafydd). + (2) in the posix SocketReceiveMultiplexer::Run() method if an exception + was thrown while listening. + + - Fixed bug in posix SocketReceiveMultiplexer::Run() that would cause + packets to stop being received if select() returned EINTR. + (thanks to Björn Wöldecke) + + - Updated and improved Makefile to avoid redundant re-linking + (thanks to Douglas Mandell) + + - Added CMakeLists.txt CMake build file (2010, thanks to David Doria) + + - Switched license to plain MIT license with non binding request + for contribution of improvements (same as current PortAudio + boilerplate). See LICENSE file. + +Thanks to Tim Blechmann, Rob Canning, Gwydion ap Dafydd, David Doria, +Christopher Delaney, Jon McCormack, Douglas Mandell, Björn Wöldecke, +all the guys at openFrameworks, and everyone who reported bugs, +submitted patches and helped out with testing this release. + +Thanks to Syneme at the University of Calgary for providing financial +support for the 1.1.0 update. + + +September 28, 2005 +------------------ + +Compared to the previous official snapshot (November 2004) the +current version of oscpack includes a re-written set of network +classes and some changes to the syntax of the networking code. It no +longer uses threads, which means that you don't need to use sleep() +if you are writing a simple single-threaded server, or you need to +spawn your own threads in a more complex application. + +The list below summarises the changes if you are porting code from +the previous release. + + - There are no longer any threads in oscpack. if you need to + set up an asynchronous listener you can create your own thread + and call Run on an instance of SocketReceiveMultiplexer or + UdpListeningReceiveSocket (see ip/UdpSocket.h) yourself. + + - Host byte order is now used for network (IP) addresses + + - Functions which used to take two parameters + now take an instance of IpEndpointName (see + ip/IpEndpointName.h) this class has a number of convenient + constructors for converting numbers and strings to internet + addresses. For example there is one which takes a string and + another that take the dotted address components as separate + parameters. + + - The UdpTransmitPort class, formerly in UdpTransmitPort.h, is + now called UdpTransmitSocket, which is simply a convenience + class derived from UdpSocket (see ip/UdpSocket.h). Where you + used to use the constructor UdpTransmitPort( address, port) now + you can use UdpTransmitSocket( IpEndpointName( address, port ) + ) or you can any of the other possible ctors to IpEndpointName + () (see above). The Send() method is unchanged. + + - The packet listener base class is now located in + ip/PacketListener.h instead of PacketListenerPort.h. The + ProcessPacket method now has an additional parameter indicating + the remote endpoint + + - The preferred way to set up listeners is with + SocketReceiveMultiplexer (in ip/UdpSocket.h), this also allows + attaching periodic timers. For simple applications which only + listen to a single socket with no timers you can use + UdpListeningReceiveSocket (also in UdpSocket.h) See + osc/OscReceiveTest.cpp or osc/OscDump.cpp for examples of this. + This is more or less equivalent to the UdpPacketListenerPort + object in the old oscpack versions except that you need to + explicitly call Run() before it will start receiving packets + and it runs in the same thread, not a separate thread so Run() + won't usually return. + + - Explicit calls to InitializeNetworking() and + TerminateNetworking() are no longer required for simple + applications (more complex windows applications should + instantiate NetworkInitializer in main() or WinMain (see + ip/NetworkingUtils.h/.cpp) + + - The OscPacketListener base class (OscPacketListener.h) was + added to make traversing OSC packets easier, it handles bundle + traversal automatically so you only need to process messages in + your derived classes. + + - On Windows be sure to link with ws2_32.lib or you will see + a linker error about WSAEventSelect not being found. Also you + will need to link with winmm.lib for timeGetTime() + diff --git a/modules/touch/ext/libTUIO2/oscpack/LICENSE b/modules/touch/ext/libTUIO2/oscpack/LICENSE new file mode 100644 index 0000000000..ebaaac1977 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/LICENSE @@ -0,0 +1,34 @@ +oscpack -- Open Sound Control (OSC) packet manipulation library +http://www.rossbencina.com/code/oscpack + +Copyright (c) 2004-2013 Ross Bencina + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files +(the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +### + +The text above constitutes the entire oscpack license; however, +the oscpack developer(s) also make the following non-binding requests: + +Any person wishing to distribute modifications to the Software is +requested to send the modifications to the original developer so that +they can be incorporated into the canonical version. It is also +requested that these non-binding requests be included whenever the +above license is reproduced. \ No newline at end of file diff --git a/modules/touch/ext/libTUIO2/oscpack/README b/modules/touch/ext/libTUIO2/oscpack/README new file mode 100644 index 0000000000..5d1d5c1216 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/README @@ -0,0 +1,150 @@ +oscpack -- Open Sound Control packet manipulation library +A simple C++ library for packing and unpacking OSC packets. +http://www.rossbencina.com/code/oscpack + +Copyright (c) 2004-2013 Ross Bencina + + +Oscpack is simply a set of C++ classes for packing and unpacking OSC packets. +Oscpack includes a minimal set of UDP networking classes for Windows and POSIX. +The networking classes are sufficient for writing many OSC applications and servers, +but you are encouraged to use another networking framework if it better suits your needs. +Oscpack is not an OSC application framework. It doesn't include infrastructure for +constructing or routing OSC namespaces, just classes for easily constructing, +sending, receiving and parsing OSC packets. The library should also be easy to use +for other transport methods (e.g. serial). + +The key goals of the oscpack library are: + + - Be a simple and complete implementation of OSC + - Be portable to a wide variety of platforms + - Allow easy development of robust OSC applications + (for example it should be impossible to crash a server + by sending it malformed packets, and difficult to create + malformed packets.) + +Here's a quick run down of the key files: + +osc/OscReceivedElements -- classes for parsing a packet +osc/OscPrintRecievedElements -- iostream << operators for printing packet elements +osc/OscOutboundPacketStream -- a class for packing messages into a packet +osc/OscPacketListener -- base class for listening to OSC packets on a UdpSocket +ip/IpEndpointName -- class that represents an IP address and port number +ip/UdpSocket -- classes for UDP transmission and listening sockets +tests/OscUnitTests -- unit test program for the OSC modules +tests/OscSendTests -- examples of how to send messages +tests/OscReceiveTest -- example of how to receive the messages sent by OSCSendTests +examples/OscDump -- a program that prints received OSC packets +examples/SimpleSend -- a minimal program to send an OSC message +examples/SimpleReceive -- a minimal program to receive an OSC message + +osc/ contains all of the OSC related classes +ip/ contains the networking classes + +ip/windows contains the Windows implementation of the networking classes +ip/posix contains the POSIX implementation of the networking classes + + +Building +-------- + +The idea is that you will embed this source code in your projects as you +see fit. The Makefile has an install rule for building a shared library and +installing headers in usr/local. It can also build a static library. +There is a CMakeLists.txt for building with cmake. + +Makefile builds +............... + +The Makefile works for Linux and Max OS X. It should also work on other platforms +that have make. Just run: + +$ make + +You can run "make install" if you like. + + +Cmake builds +............ + +There is a CMakeLists.txt file which has been tested with cmake on +Windows and Linux. It should work on other platforms too. +For example, to generate a Visual Studio 10 project, run cmake +like this: + +> cmake -G "Visual Studio 10" + +Run cmake without any parameters to get a list of available generators. + + +Mingw build batch file +...................... + +For Windows there is a batch file for doing a simple test build with +MinGW gcc called make.MinGW32.bat. This will build the test executables +and oscdump in ./bin and run the unit tests. + + +Note: + +In some rare instances you may need to edit the Makefile or +osc/OscHostEndianness.h to configure oscpack for the endianness of your +processor (see the comments at the top of the Makefile for details). + + + +Verification test +----------------- + +To run the unit tests: + +$ ./bin/OscUnitTests + +To run the send and receive tests. Open two terminals. In one run: + +$ ./bin/OscReceiveTest + +Then in the other terminal run: + +$./bin/OscSendTests + + +You should see an indication that the messages were received +in the first terminal. + +Note that OscSendTests intentionally sends some unexpected +message parameters to test exception handling in the receiver. +You will see some "error while parsing message" messages printed. + +You can use ./bin/OscDump to print out OSC messages received +from any program, including the test programs. + + +-- + + +If you fix anything or write a set of TCP send/receive classes +please consider sending me a patch. My email address is +rossb@audiomulch.com. Thanks :) + +For more information about Open Sound Control, see: +http://opensoundcontrol.org/ + +Thanks to Till Bovermann for helping with POSIX networking code and +Mac compatibility, and to Martin Kaltenbrunner and the rest of the +reacTable team for giving me a reason to finish this library. Thanks +to Merlijn Blaauw for reviewing the interfaces. Thanks to Xavier Oliver +for additional help with Linux builds and POSIX implementation details. + +Portions developed at the Music Technology Group, Audiovisual Institute, +University Pompeu Fabra, Barcelona, during my stay as a visiting +researcher, November 2004 - September 2005. + +Thanks to Syneme at the University of Calgary for providing financial +support for the 1.1.0 update, December 2012 - March 2013. + +See the file CHANGES for information about recent updates. + +See the file LICENSE for information about distributing and using this code. + +### diff --git a/modules/touch/ext/libTUIO2/oscpack/TODO b/modules/touch/ext/libTUIO2/oscpack/TODO new file mode 100644 index 0000000000..112f02eab5 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/TODO @@ -0,0 +1,52 @@ +TODO: + + - consider adding the local endpoint name to PacketListener::PacketReceived() params + + - consider adding ListenerThread class to support old seperate thread listener functionality, something like: + + class UdpSocketListenerThread{ + public: + UdpSocketListenerThread( UdpSocket& socket, Listener *listener ); + UdpSocketListenerThread( UdpSocketReceiveMultiplexer *mux ); + ~UdpSocketListenerThread(); + + void Run(); + void Stop(); + }; + + - work out a way to make the parsing classes totally safe. at a minimum this + means adding functions to test for invalid float/doublevalues, + making sure the iterators never pass the end of the message, ... + (passing end of message can happen if: + - too many args in type tags + a. typetags overflow message size + b. args fulfilling typetags overflow message size + - strings too long or not terminated correctly + - blobs too long or not terminated correctly + + if the message was fully checked during construction, the end() iterator + could be moved back until only arguments which fit withing size() may + be interated (this could be none). A flag could be set to indicate that + something was wrong. + + - other packet badness could include: + - time tags too far into the future (the scheduler should deal with + that i guess). + - message address patterns which aren't correctly terminated + + - improve the ability to parse messages without tags (SC uses methods which + get the data and advance the iterator in one step.) + - Check* could be modified to do this - ie if typetags are not present + it could check that reading the field won't escape the message size + and return the data, or return false if some consistency + constraint is violated. + (or alternately drop support for messages without type tags) + + + - add a method to discard an inprogress message if it gets half + constructed and the buffer is full in OutboundPacket + + - write a stress testing app which can send garbage packets to try to flush out other bugs in the parsing code. + + + diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.cpp b/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.cpp new file mode 100644 index 0000000000..50b0262216 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.cpp @@ -0,0 +1,88 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "IpEndpointName.h" + +#include + +#include "NetworkingUtils.h" + + +unsigned long IpEndpointName::GetHostByName( const char *s ) +{ + return ::GetHostByName(s); +} + + +void IpEndpointName::AddressAsString( char *s ) const +{ + if( address == ANY_ADDRESS ){ + std::sprintf( s, "" ); + }else{ + std::sprintf( s, "%d.%d.%d.%d", + (int)((address >> 24) & 0xFF), + (int)((address >> 16) & 0xFF), + (int)((address >> 8) & 0xFF), + (int)(address & 0xFF) ); + } +} + + +void IpEndpointName::AddressAndPortAsString( char *s ) const +{ + if( port == ANY_PORT ){ + if( address == ANY_ADDRESS ){ + std::sprintf( s, ":" ); + }else{ + std::sprintf( s, "%d.%d.%d.%d:", + (int)((address >> 24) & 0xFF), + (int)((address >> 16) & 0xFF), + (int)((address >> 8) & 0xFF), + (int)(address & 0xFF) ); + } + }else{ + if( address == ANY_ADDRESS ){ + std::sprintf( s, ":%d", port ); + }else{ + std::sprintf( s, "%d.%d.%d.%d:%d", + (int)((address >> 24) & 0xFF), + (int)((address >> 16) & 0xFF), + (int)((address >> 8) & 0xFF), + (int)(address & 0xFF), + (int)port ); + } + } +} diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.h b/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.h new file mode 100644 index 0000000000..c83e1c3cfe --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.h @@ -0,0 +1,83 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_IPENDPOINTNAME_H +#define INCLUDED_OSCPACK_IPENDPOINTNAME_H + + +class IpEndpointName{ + static unsigned long GetHostByName( const char *s ); +public: + static const unsigned long ANY_ADDRESS = 0xFFFFFFFF; + static const int ANY_PORT = -1; + + IpEndpointName() + : address( ANY_ADDRESS ), port( ANY_PORT ) {} + IpEndpointName( int port_ ) + : address( ANY_ADDRESS ), port( port_ ) {} + IpEndpointName( unsigned long ipAddress_, int port_ ) + : address( ipAddress_ ), port( port_ ) {} + IpEndpointName( const char *addressName, int port_=ANY_PORT ) + : address( GetHostByName( addressName ) ) + , port( port_ ) {} + IpEndpointName( int addressA, int addressB, int addressC, int addressD, int port_=ANY_PORT ) + : address( ( (addressA << 24) | (addressB << 16) | (addressC << 8) | addressD ) ) + , port( port_ ) {} + + // address and port are maintained in host byte order here + unsigned long address; + int port; + + bool IsMulticastAddress() const { return ((address >> 24) & 0xFF) >= 224 && ((address >> 24) & 0xFF) <= 239; } + + enum { ADDRESS_STRING_LENGTH=17 }; + void AddressAsString( char *s ) const; + + enum { ADDRESS_AND_PORT_STRING_LENGTH=23}; + void AddressAndPortAsString( char *s ) const; +}; + +inline bool operator==( const IpEndpointName& lhs, const IpEndpointName& rhs ) +{ + return (lhs.address == rhs.address && lhs.port == rhs.port ); +} + +inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs ) +{ + return !(lhs == rhs); +} + +#endif /* INCLUDED_OSCPACK_IPENDPOINTNAME_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/NetworkingUtils.h b/modules/touch/ext/libTUIO2/oscpack/ip/NetworkingUtils.h new file mode 100644 index 0000000000..a83612aeda --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/NetworkingUtils.h @@ -0,0 +1,56 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_NETWORKINGUTILS_H +#define INCLUDED_OSCPACK_NETWORKINGUTILS_H + + +// in general NetworkInitializer is only used internally, but if you're +// application creates multiple sockets from different threads at runtime you +// should instantiate one of these in main just to make sure the networking +// layer is initialized. +class NetworkInitializer{ +public: + NetworkInitializer(); + ~NetworkInitializer(); +}; + + +// return ip address of host name in host byte order +unsigned long GetHostByName( const char *name ); + + +#endif /* INCLUDED_OSCPACK_NETWORKINGUTILS_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/PacketListener.h b/modules/touch/ext/libTUIO2/oscpack/ip/PacketListener.h new file mode 100644 index 0000000000..6c26b32996 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/PacketListener.h @@ -0,0 +1,50 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_PACKETLISTENER_H +#define INCLUDED_OSCPACK_PACKETLISTENER_H + + +class IpEndpointName; + +class PacketListener{ +public: + virtual ~PacketListener() {} + virtual void ProcessPacket( const char *data, int size, + const IpEndpointName& remoteEndpoint ) = 0; +}; + +#endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/TimerListener.h b/modules/touch/ext/libTUIO2/oscpack/ip/TimerListener.h new file mode 100644 index 0000000000..59b4040600 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/TimerListener.h @@ -0,0 +1,47 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_TIMERLISTENER_H +#define INCLUDED_OSCPACK_TIMERLISTENER_H + + +class TimerListener{ +public: + virtual ~TimerListener() {} + virtual void TimerExpired() = 0; +}; + +#endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/UdpSocket.h b/modules/touch/ext/libTUIO2/oscpack/ip/UdpSocket.h new file mode 100644 index 0000000000..2d7a189a1b --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/UdpSocket.h @@ -0,0 +1,176 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_UDPSOCKET_H +#define INCLUDED_OSCPACK_UDPSOCKET_H + +#include // size_t + +#include "NetworkingUtils.h" +#include "IpEndpointName.h" + + +class PacketListener; +class TimerListener; + +class UdpSocket; + +class SocketReceiveMultiplexer{ + class Implementation; + Implementation *impl_; + + friend class UdpSocket; + +public: + SocketReceiveMultiplexer(); + ~SocketReceiveMultiplexer(); + + // only call the attach/detach methods _before_ calling Run + + // only one listener per socket, each socket at most once + void AttachSocketListener( UdpSocket *socket, PacketListener *listener ); + void DetachSocketListener( UdpSocket *socket, PacketListener *listener ); + + void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ); + void AttachPeriodicTimerListener( + int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ); + void DetachPeriodicTimerListener( TimerListener *listener ); + + void Run(); // loop and block processing messages indefinitely + void RunUntilSigInt(); + void Break(); // call this from a listener to exit once the listener returns + void AsynchronousBreak(); // call this from another thread or signal handler to exit the Run() state +}; + + +class UdpSocket{ + class Implementation; + Implementation *impl_; + + friend class SocketReceiveMultiplexer::Implementation; + +public: + + // Ctor throws std::runtime_error if there's a problem + // initializing the socket. + UdpSocket(); + virtual ~UdpSocket(); + + // Enable broadcast addresses (e.g. x.x.x.255) + // Sets SO_BROADCAST socket option. + void SetEnableBroadcast( bool enableBroadcast ); + + // Enable multiple listeners for a single port on same + // network interface* + // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X). + // [*] The exact behavior of SO_REUSEADDR and + // SO_REUSEPORT is undefined for some common cases + // and may have drastically different behavior on different + // operating systems. + void SetAllowReuse( bool allowReuse ); + + + // The socket is created in an unbound, unconnected state + // such a socket can only be used to send to an arbitrary + // address using SendTo(). To use Send() you need to first + // connect to a remote endpoint using Connect(). To use + // ReceiveFrom you need to first bind to a local endpoint + // using Bind(). + + // Retrieve the local endpoint name when sending to 'to' + IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const; + + // Connect to a remote endpoint which is used as the target + // for calls to Send() + void Connect( const IpEndpointName& remoteEndpoint ); + void Send( const char *data, std::size_t size ); + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ); + + + // Bind a local endpoint to receive incoming data. Endpoint + // can be 'any' for the system to choose an endpoint + void Bind( const IpEndpointName& localEndpoint ); + bool IsBound() const; + + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ); +}; + + +// convenience classes for transmitting and receiving +// they just call Connect and/or Bind in the ctor. +// note that you can still use a receive socket +// for transmitting etc + +class UdpTransmitSocket : public UdpSocket{ +public: + UdpTransmitSocket( const IpEndpointName& remoteEndpoint ) + { Connect( remoteEndpoint ); } +}; + + +class UdpReceiveSocket : public UdpSocket{ +public: + UdpReceiveSocket( const IpEndpointName& localEndpoint ) + { Bind( localEndpoint ); } +}; + + +// UdpListeningReceiveSocket provides a simple way to bind one listener +// to a single socket without having to manually set up a SocketReceiveMultiplexer + +class UdpListeningReceiveSocket : public UdpSocket{ + SocketReceiveMultiplexer mux_; + PacketListener *listener_; +public: + UdpListeningReceiveSocket( const IpEndpointName& localEndpoint, PacketListener *listener ) + : listener_( listener ) + { + Bind( localEndpoint ); + mux_.AttachSocketListener( this, listener_ ); + } + + ~UdpListeningReceiveSocket() + { mux_.DetachSocketListener( this, listener_ ); } + + // see SocketReceiveMultiplexer above for the behaviour of these methods... + void Run() { mux_.Run(); } + void RunUntilSigInt() { mux_.RunUntilSigInt(); } + void Break() { mux_.Break(); } + void AsynchronousBreak() { mux_.AsynchronousBreak(); } +}; + + +#endif /* INCLUDED_OSCPACK_UDPSOCKET_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/posix/NetworkingUtils.cpp b/modules/touch/ext/libTUIO2/oscpack/ip/posix/NetworkingUtils.cpp new file mode 100644 index 0000000000..720abc207e --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/posix/NetworkingUtils.cpp @@ -0,0 +1,64 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "oscpack/ip/NetworkingUtils.h" + +#include +#include +#include + +#include + + + +NetworkInitializer::NetworkInitializer() {} + +NetworkInitializer::~NetworkInitializer() {} + + +unsigned long GetHostByName( const char *name ) +{ + unsigned long result = 0; + + struct hostent *h = gethostbyname( name ); + if( h ){ + struct in_addr a; + std::memcpy( &a, h->h_addr_list[0], h->h_length ); + result = ntohl(a.s_addr); + } + + return result; +} diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/posix/UdpSocket.cpp b/modules/touch/ext/libTUIO2/oscpack/ip/posix/UdpSocket.cpp new file mode 100644 index 0000000000..f0f1afbb78 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/posix/UdpSocket.cpp @@ -0,0 +1,602 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "oscpack/ip/UdpSocket.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include // for sockaddr_in + +#include +#include +#include +#include + +#include +#include +#include // for memset +#include +#include + +#include "oscpack/ip/PacketListener.h" +#include "oscpack/ip/TimerListener.h" + + +#if defined(__APPLE__) && !defined(_SOCKLEN_T) +// pre system 10.3 didn't have socklen_t +typedef ssize_t socklen_t; +#endif + + +static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) +{ + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + sockAddr.sin_family = AF_INET; + + sockAddr.sin_addr.s_addr = + (endpoint.address == IpEndpointName::ANY_ADDRESS) + ? INADDR_ANY + : htonl( endpoint.address ); + + sockAddr.sin_port = + (endpoint.port == IpEndpointName::ANY_PORT) + ? 0 + : htons( endpoint.port ); +} + + +static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr ) +{ + return IpEndpointName( + (sockAddr.sin_addr.s_addr == INADDR_ANY) + ? IpEndpointName::ANY_ADDRESS + : ntohl( sockAddr.sin_addr.s_addr ), + (sockAddr.sin_port == 0) + ? IpEndpointName::ANY_PORT + : ntohs( sockAddr.sin_port ) + ); +} + + +class UdpSocket::Implementation{ + bool isBound_; + bool isConnected_; + + int socket_; + struct sockaddr_in connectedAddr_; + struct sockaddr_in sendToAddr_; + +public: + + Implementation() + : isBound_( false ) + , isConnected_( false ) + , socket_( -1 ) + { + if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 ){ + throw std::runtime_error("unable to create udp socket\n"); + } + + std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); + sendToAddr_.sin_family = AF_INET; + } + + ~Implementation() + { + if (socket_ != -1) close(socket_); + } + + void SetEnableBroadcast( bool enableBroadcast ) + { + int broadcast = (enableBroadcast) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + } + + void SetAllowReuse( bool allowReuse ) + { + int reuseAddr = (allowReuse) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); + +#ifdef __APPLE__ + // needed also for OS X - enable multiple listeners for a single port on same network interface + int reusePort = (allowReuse) ? 1 : 0; // int on posix + setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)); +#endif + } + + IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const + { + assert( isBound_ ); + + // first connect the socket to the remote server + + struct sockaddr_in connectSockAddr; + SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint ); + + if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) { + throw std::runtime_error("unable to connect udp socket\n"); + } + + // get the address + + struct sockaddr_in sockAddr; + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + socklen_t length = sizeof(sockAddr); + if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { + throw std::runtime_error("unable to getsockname\n"); + } + + if( isConnected_ ){ + // reconnect to the connected address + + if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { + throw std::runtime_error("unable to connect udp socket\n"); + } + + }else{ + // unconnect from the remote address + + struct sockaddr_in unconnectSockAddr; + std::memset( (char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr ) ); + unconnectSockAddr.sin_family = AF_UNSPEC; + // address fields are zero + int connectResult = connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)); + if ( connectResult < 0 && errno != EAFNOSUPPORT ) { + throw std::runtime_error("unable to un-connect udp socket\n"); + } + } + + return IpEndpointNameFromSockaddr( sockAddr ); + } + + void Connect( const IpEndpointName& remoteEndpoint ) + { + SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint ); + + if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { + throw std::runtime_error("unable to connect udp socket\n"); + } + + isConnected_ = true; + } + + void Send( const char *data, std::size_t size ) + { + assert( isConnected_ ); + + send( socket_, data, size, 0 ); + } + + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) + { + sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); + sendToAddr_.sin_port = htons( remoteEndpoint.port ); + + sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); + } + + void Bind( const IpEndpointName& localEndpoint ) + { + struct sockaddr_in bindSockAddr; + SockaddrFromIpEndpointName( bindSockAddr, localEndpoint ); + + if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) { + throw std::runtime_error("unable to bind udp socket\n"); + } + + isBound_ = true; + } + + bool IsBound() const { return isBound_; } + + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) + { + assert( isBound_ ); + + struct sockaddr_in fromAddr; + socklen_t fromAddrLen = sizeof(fromAddr); + + ssize_t result = recvfrom(socket_, data, size, 0, + (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); + if( result < 0 ) + return 0; + + remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr); + remoteEndpoint.port = ntohs(fromAddr.sin_port); + + return (std::size_t)result; + } + + int Socket() { return socket_; } +}; + +UdpSocket::UdpSocket() +{ + impl_ = new Implementation(); +} + +UdpSocket::~UdpSocket() +{ + delete impl_; +} + +void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) +{ + impl_->SetEnableBroadcast( enableBroadcast ); +} + +void UdpSocket::SetAllowReuse( bool allowReuse ) +{ + impl_->SetAllowReuse( allowReuse ); +} + +IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const +{ + return impl_->LocalEndpointFor( remoteEndpoint ); +} + +void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) +{ + impl_->Connect( remoteEndpoint ); +} + +void UdpSocket::Send( const char *data, std::size_t size ) +{ + impl_->Send( data, size ); +} + +void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) +{ + impl_->SendTo( remoteEndpoint, data, size ); +} + +void UdpSocket::Bind( const IpEndpointName& localEndpoint ) +{ + impl_->Bind( localEndpoint ); +} + +bool UdpSocket::IsBound() const +{ + return impl_->IsBound(); +} + +std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) +{ + return impl_->ReceiveFrom( remoteEndpoint, data, size ); +} + + +struct AttachedTimerListener{ + AttachedTimerListener( int id, int p, TimerListener *tl ) + : initialDelayMs( id ) + , periodMs( p ) + , listener( tl ) {} + int initialDelayMs; + int periodMs; + TimerListener *listener; +}; + + +static bool CompareScheduledTimerCalls( + const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs ) +{ + return lhs.first < rhs.first; +} + + +SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0; + +extern "C" /*static*/ void InterruptSignalHandler( int ); +/*static*/ void InterruptSignalHandler( int ) +{ + multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak(); + signal( SIGINT, SIG_DFL ); +} + + +class SocketReceiveMultiplexer::Implementation{ + std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; + std::vector< AttachedTimerListener > timerListeners_; + + volatile bool break_; + int breakPipe_[2]; // [0] is the reader descriptor and [1] the writer + + double GetCurrentTimeMs() const + { + struct timeval t; + + gettimeofday( &t, 0 ); + + return ((double)t.tv_sec*1000.) + ((double)t.tv_usec / 1000.); + } + +public: + Implementation() + { + if( pipe(breakPipe_) != 0 ) + throw std::runtime_error( "creation of asynchronous break pipes failed\n" ); + } + + ~Implementation() + { + close( breakPipe_[0] ); + close( breakPipe_[1] ); + } + + void AttachSocketListener( UdpSocket *socket, PacketListener *listener ) + { + assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() ); + // we don't check that the same socket has been added multiple times, even though this is an error + socketListeners_.push_back( std::make_pair( listener, socket ) ); + } + + void DetachSocketListener( UdpSocket *socket, PacketListener *listener ) + { + std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = + std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ); + assert( i != socketListeners_.end() ); + + socketListeners_.erase( i ); + } + + void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) + { + timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) ); + } + + void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) + { + timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) ); + } + + void DetachPeriodicTimerListener( TimerListener *listener ) + { + std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); + while( i != timerListeners_.end() ){ + if( i->listener == listener ) + break; + ++i; + } + + assert( i != timerListeners_.end() ); + + timerListeners_.erase( i ); + } + + void Run() + { + break_ = false; + char *data = 0; + + try{ + + // configure the master fd_set for select() + + fd_set masterfds, tempfds; + FD_ZERO( &masterfds ); + FD_ZERO( &tempfds ); + + // in addition to listening to the inbound sockets we + // also listen to the asynchronous break pipe, so that AsynchronousBreak() + // can break us out of select() from another thread. + FD_SET( breakPipe_[0], &masterfds ); + int fdmax = breakPipe_[0]; + + for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); + i != socketListeners_.end(); ++i ){ + + if( fdmax < i->second->impl_->Socket() ) + fdmax = i->second->impl_->Socket(); + FD_SET( i->second->impl_->Socket(), &masterfds ); + } + + + // configure the timer queue + double currentTimeMs = GetCurrentTimeMs(); + + // expiry time ms, listener + std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; + for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); + i != timerListeners_.end(); ++i ) + timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); + std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); + + const int MAX_BUFFER_SIZE = 4098; + data = new char[ MAX_BUFFER_SIZE ]; + IpEndpointName remoteEndpoint; + + struct timeval timeout; + + while( !break_ ){ + tempfds = masterfds; + + struct timeval *timeoutPtr = 0; + if( !timerQueue_.empty() ){ + double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs(); + if( timeoutMs < 0 ) + timeoutMs = 0; + + long timoutSecondsPart = (long)(timeoutMs * .001); + timeout.tv_sec = (time_t)timoutSecondsPart; + // 1000000 microseconds in a second + timeout.tv_usec = (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000); + timeoutPtr = &timeout; + } + + if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 ){ + if( break_ ){ + break; + }else if( errno == EINTR ){ + // on returning an error, select() doesn't clear tempfds. + // so tempfds would remain all set, which would cause read( breakPipe_[0]... + // below to block indefinitely. therefore if select returns EINTR we restart + // the while() loop instead of continuing on to below. + continue; + }else{ + throw std::runtime_error("select failed\n"); + } + } + + if( FD_ISSET( breakPipe_[0], &tempfds ) ){ + // clear pending data from the asynchronous break pipe + char c; + read( breakPipe_[0], &c, 1 ); + } + + if( break_ ) + break; + + for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); + i != socketListeners_.end(); ++i ){ + + if( FD_ISSET( i->second->impl_->Socket(), &tempfds ) ){ + + std::size_t size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); + if( size > 0 ){ + i->first->ProcessPacket( data, (int)size, remoteEndpoint ); + if( break_ ) + break; + } + } + } + + // execute any expired timers + currentTimeMs = GetCurrentTimeMs(); + bool resort = false; + for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); + i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ + + i->second.listener->TimerExpired(); + if( break_ ) + break; + + i->first += i->second.periodMs; + resort = true; + } + if( resort ) + std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); + } + + delete [] data; + }catch(...){ + if( data ) + delete [] data; + throw; + } + } + + void Break() + { + break_ = true; + } + + void AsynchronousBreak() + { + break_ = true; + + // Send a termination message to the asynchronous break pipe, so select() will return + write( breakPipe_[1], "!", 1 ); + } +}; + + + +SocketReceiveMultiplexer::SocketReceiveMultiplexer() +{ + impl_ = new Implementation(); +} + +SocketReceiveMultiplexer::~SocketReceiveMultiplexer() +{ + delete impl_; +} + +void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener ) +{ + impl_->AttachSocketListener( socket, listener ); +} + +void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener ) +{ + impl_->DetachSocketListener( socket, listener ); +} + +void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) +{ + impl_->AttachPeriodicTimerListener( periodMilliseconds, listener ); +} + +void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) +{ + impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ); +} + +void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener ) +{ + impl_->DetachPeriodicTimerListener( listener ); +} + +void SocketReceiveMultiplexer::Run() +{ + impl_->Run(); +} + +void SocketReceiveMultiplexer::RunUntilSigInt() +{ + assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */ + multiplexerInstanceToAbortWithSigInt_ = this; + signal( SIGINT, InterruptSignalHandler ); + impl_->Run(); + signal( SIGINT, SIG_DFL ); + multiplexerInstanceToAbortWithSigInt_ = 0; +} + +void SocketReceiveMultiplexer::Break() +{ + impl_->Break(); +} + +void SocketReceiveMultiplexer::AsynchronousBreak() +{ + impl_->AsynchronousBreak(); +} + diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/win32/NetworkingUtils.cpp b/modules/touch/ext/libTUIO2/oscpack/ip/win32/NetworkingUtils.cpp new file mode 100644 index 0000000000..487cfa38a0 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/win32/NetworkingUtils.cpp @@ -0,0 +1,95 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "oscpack/ip/NetworkingUtils.h" + +#include // this must come first to prevent errors with MSVC7 +#include + +#include + + +static LONG initCount_ = 0; +static bool winsockInitialized_ = false; + +NetworkInitializer::NetworkInitializer() +{ + if( InterlockedIncrement( &initCount_ ) == 1 ){ + // there is a race condition here if one thread tries to access + // the library while another is still initializing it. + // i can't think of an easy way to fix it so i'm telling you here + // incase you need to init the library from two threads at once. + // this is why the header file advises to instantiate one of these + // in main() so that the initialization happens globally + + // initialize winsock + WSAData wsaData; + int nCode = WSAStartup(MAKEWORD(1, 1), &wsaData); + if( nCode != 0 ){ + //std::cout << "WSAStartup() failed with error code " << nCode << "\n"; + }else{ + winsockInitialized_ = true; + } + } +} + + +NetworkInitializer::~NetworkInitializer() +{ + if( InterlockedDecrement( &initCount_ ) == 0 ){ + if( winsockInitialized_ ){ + WSACleanup(); + winsockInitialized_ = false; + } + } +} + + +unsigned long GetHostByName( const char *name ) +{ + NetworkInitializer networkInitializer; + + unsigned long result = 0; + + struct hostent *h = gethostbyname( name ); + if( h ){ + struct in_addr a; + std::memcpy( &a, h->h_addr_list[0], h->h_length ); + result = ntohl(a.s_addr); + } + + return result; +} diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/win32/UdpSocket.cpp b/modules/touch/ext/libTUIO2/oscpack/ip/win32/UdpSocket.cpp new file mode 100644 index 0000000000..57cff3f5bf --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/ip/win32/UdpSocket.cpp @@ -0,0 +1,571 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ + +#include // this must come first to prevent errors with MSVC7 +#include +#include // for timeGetTime() + +#ifndef WINCE +#include +#endif + +#include +#include +#include // for memset +#include +#include + +#include "oscpack/ip/UdpSocket.h" // usually I'd include the module header first + // but this is causing conflicts with BCB4 due to + // std::size_t usage. + +#include "oscpack/ip/NetworkingUtils.h" +#include "oscpack/ip/PacketListener.h" +#include "oscpack/ip/TimerListener.h" + + +typedef int socklen_t; + + +static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) +{ + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + sockAddr.sin_family = AF_INET; + + sockAddr.sin_addr.s_addr = + (endpoint.address == IpEndpointName::ANY_ADDRESS) + ? INADDR_ANY + : htonl( endpoint.address ); + + sockAddr.sin_port = + (endpoint.port == IpEndpointName::ANY_PORT) + ? (short)0 + : htons( (short)endpoint.port ); +} + + +static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr ) +{ + return IpEndpointName( + (sockAddr.sin_addr.s_addr == INADDR_ANY) + ? IpEndpointName::ANY_ADDRESS + : ntohl( sockAddr.sin_addr.s_addr ), + (sockAddr.sin_port == 0) + ? IpEndpointName::ANY_PORT + : ntohs( sockAddr.sin_port ) + ); +} + + +class UdpSocket::Implementation{ + NetworkInitializer networkInitializer_; + + bool isBound_; + bool isConnected_; + + SOCKET socket_; + struct sockaddr_in connectedAddr_; + struct sockaddr_in sendToAddr_; + +public: + + Implementation() + : isBound_( false ) + , isConnected_( false ) + , socket_( INVALID_SOCKET ) + { + if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == INVALID_SOCKET ){ + throw std::runtime_error("unable to create udp socket\n"); + } + + std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); + sendToAddr_.sin_family = AF_INET; + } + + ~Implementation() + { + if (socket_ != INVALID_SOCKET) closesocket(socket_); + } + + void SetEnableBroadcast( bool enableBroadcast ) + { + char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32 + setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + } + + void SetAllowReuse( bool allowReuse ) + { + // Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article: + // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" + // http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx + + char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32 + setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); + } + + IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const + { + assert( isBound_ ); + + // first connect the socket to the remote server + + struct sockaddr_in connectSockAddr; + SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint ); + + if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) { + throw std::runtime_error("unable to connect udp socket\n"); + } + + // get the address + + struct sockaddr_in sockAddr; + std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); + socklen_t length = sizeof(sockAddr); + if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { + throw std::runtime_error("unable to getsockname\n"); + } + + if( isConnected_ ){ + // reconnect to the connected address + + if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { + throw std::runtime_error("unable to connect udp socket\n"); + } + + }else{ + // unconnect from the remote address + + struct sockaddr_in unconnectSockAddr; + SockaddrFromIpEndpointName( unconnectSockAddr, IpEndpointName() ); + + if( connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)) < 0 + && WSAGetLastError() != WSAEADDRNOTAVAIL ){ + throw std::runtime_error("unable to un-connect udp socket\n"); + } + } + + return IpEndpointNameFromSockaddr( sockAddr ); + } + + void Connect( const IpEndpointName& remoteEndpoint ) + { + SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint ); + + if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { + throw std::runtime_error("unable to connect udp socket\n"); + } + + isConnected_ = true; + } + + void Send( const char *data, std::size_t size ) + { + assert( isConnected_ ); + + send( socket_, data, (int)size, 0 ); + } + + void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) + { + sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); + sendToAddr_.sin_port = htons( (short)remoteEndpoint.port ); + + sendto( socket_, data, (int)size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); + } + + void Bind( const IpEndpointName& localEndpoint ) + { + struct sockaddr_in bindSockAddr; + SockaddrFromIpEndpointName( bindSockAddr, localEndpoint ); + + if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) { + throw std::runtime_error("unable to bind udp socket\n"); + } + + isBound_ = true; + } + + bool IsBound() const { return isBound_; } + + std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) + { + assert( isBound_ ); + + struct sockaddr_in fromAddr; + socklen_t fromAddrLen = sizeof(fromAddr); + + int result = recvfrom(socket_, data, (int)size, 0, + (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); + if( result < 0 ) + return 0; + + remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr); + remoteEndpoint.port = ntohs(fromAddr.sin_port); + + return result; + } + + SOCKET& Socket() { return socket_; } +}; + +UdpSocket::UdpSocket() +{ + impl_ = new Implementation(); +} + +UdpSocket::~UdpSocket() +{ + delete impl_; +} + +void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) +{ + impl_->SetEnableBroadcast( enableBroadcast ); +} + +void UdpSocket::SetAllowReuse( bool allowReuse ) +{ + impl_->SetAllowReuse( allowReuse ); +} + +IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const +{ + return impl_->LocalEndpointFor( remoteEndpoint ); +} + +void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) +{ + impl_->Connect( remoteEndpoint ); +} + +void UdpSocket::Send( const char *data, std::size_t size ) +{ + impl_->Send( data, size ); +} + +void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) +{ + impl_->SendTo( remoteEndpoint, data, size ); +} + +void UdpSocket::Bind( const IpEndpointName& localEndpoint ) +{ + impl_->Bind( localEndpoint ); +} + +bool UdpSocket::IsBound() const +{ + return impl_->IsBound(); +} + +std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) +{ + return impl_->ReceiveFrom( remoteEndpoint, data, size ); +} + + +struct AttachedTimerListener{ + AttachedTimerListener( int id, int p, TimerListener *tl ) + : initialDelayMs( id ) + , periodMs( p ) + , listener( tl ) {} + int initialDelayMs; + int periodMs; + TimerListener *listener; +}; + + +static bool CompareScheduledTimerCalls( + const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs ) +{ + return lhs.first < rhs.first; +} + + +SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0; + +extern "C" /*static*/ void InterruptSignalHandler( int ); +/*static*/ void InterruptSignalHandler( int ) +{ + multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak(); +#ifndef WINCE + signal( SIGINT, SIG_DFL ); +#endif +} + + +class SocketReceiveMultiplexer::Implementation{ + NetworkInitializer networkInitializer_; + + std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; + std::vector< AttachedTimerListener > timerListeners_; + + volatile bool break_; + HANDLE breakEvent_; + + double GetCurrentTimeMs() const + { +#ifndef WINCE + return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days +#else + return 0; +#endif + } + +public: + Implementation() + { + breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL ); + } + + ~Implementation() + { + CloseHandle( breakEvent_ ); + } + + void AttachSocketListener( UdpSocket *socket, PacketListener *listener ) + { + assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() ); + // we don't check that the same socket has been added multiple times, even though this is an error + socketListeners_.push_back( std::make_pair( listener, socket ) ); + } + + void DetachSocketListener( UdpSocket *socket, PacketListener *listener ) + { + std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = + std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ); + assert( i != socketListeners_.end() ); + + socketListeners_.erase( i ); + } + + void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) + { + timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) ); + } + + void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) + { + timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) ); + } + + void DetachPeriodicTimerListener( TimerListener *listener ) + { + std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); + while( i != timerListeners_.end() ){ + if( i->listener == listener ) + break; + ++i; + } + + assert( i != timerListeners_.end() ); + + timerListeners_.erase( i ); + } + + void Run() + { + break_ = false; + + // prepare the window events which we use to wake up on incoming data + // we use this instead of select() primarily to support the AsyncBreak() + // mechanism. + + std::vector events( socketListeners_.size() + 1, 0 ); + int j=0; + for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); + i != socketListeners_.end(); ++i, ++j ){ + + HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL ); + WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below + events[j] = event; + } + + + events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event + + + // configure the timer queue + double currentTimeMs = GetCurrentTimeMs(); + + // expiry time ms, listener + std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; + for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); + i != timerListeners_.end(); ++i ) + timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); + std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); + + const int MAX_BUFFER_SIZE = 4098; + char *data = new char[ MAX_BUFFER_SIZE ]; + IpEndpointName remoteEndpoint; + + while( !break_ ){ + + double currentTimeMs = GetCurrentTimeMs(); + + DWORD waitTime = INFINITE; + if( !timerQueue_.empty() ){ + + waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs + ? timerQueue_.front().first - currentTimeMs + : 0 ); + } + + DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime ); + if( break_ ) + break; + + if( waitResult != WAIT_TIMEOUT ){ + for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){ + std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); + if( size > 0 ){ + socketListeners_[i].first->ProcessPacket( data, (int)size, remoteEndpoint ); + if( break_ ) + break; + } + } + } + + // execute any expired timers + currentTimeMs = GetCurrentTimeMs(); + bool resort = false; + for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); + i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ + + i->second.listener->TimerExpired(); + if( break_ ) + break; + + i->first += i->second.periodMs; + resort = true; + } + if( resort ) + std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); + } + + delete [] data; + + // free events + j = 0; + for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); + i != socketListeners_.end(); ++i, ++j ){ + + WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event + CloseHandle( events[j] ); + unsigned long enableNonblocking = 0; + ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again + } + } + + void Break() + { + break_ = true; + } + + void AsynchronousBreak() + { + break_ = true; + SetEvent( breakEvent_ ); + } +}; + + + +SocketReceiveMultiplexer::SocketReceiveMultiplexer() +{ + impl_ = new Implementation(); +} + +SocketReceiveMultiplexer::~SocketReceiveMultiplexer() +{ + delete impl_; +} + +void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener ) +{ + impl_->AttachSocketListener( socket, listener ); +} + +void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener ) +{ + impl_->DetachSocketListener( socket, listener ); +} + +void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) +{ + impl_->AttachPeriodicTimerListener( periodMilliseconds, listener ); +} + +void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) +{ + impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ); +} + +void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener ) +{ + impl_->DetachPeriodicTimerListener( listener ); +} + +void SocketReceiveMultiplexer::Run() +{ + impl_->Run(); +} + +void SocketReceiveMultiplexer::RunUntilSigInt() +{ + assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */ + multiplexerInstanceToAbortWithSigInt_ = this; +#ifndef WINCE + signal( SIGINT, InterruptSignalHandler ); +#endif + impl_->Run(); +#ifndef WINCE + signal( SIGINT, SIG_DFL ); +#endif + multiplexerInstanceToAbortWithSigInt_ = 0; +} + +void SocketReceiveMultiplexer::Break() +{ + impl_->Break(); +} + +void SocketReceiveMultiplexer::AsynchronousBreak() +{ + impl_->AsynchronousBreak(); +} + diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/MessageMappingOscPacketListener.h b/modules/touch/ext/libTUIO2/oscpack/osc/MessageMappingOscPacketListener.h new file mode 100644 index 0000000000..bf56b530a2 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/MessageMappingOscPacketListener.h @@ -0,0 +1,80 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H +#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H + +#include +#include + +#include "OscPacketListener.h" + + + +namespace osc{ + +template< class T > +class MessageMappingOscPacketListener : public OscPacketListener{ +public: + typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&); + +protected: + void RegisterMessageFunction( const char *addressPattern, function_type f ) + { + functions_.insert( std::make_pair( addressPattern, f ) ); + } + + virtual void ProcessMessage( const osc::ReceivedMessage& m, + const IpEndpointName& remoteEndpoint ) + { + typename function_map_type::iterator i = functions_.find( m.AddressPattern() ); + if( i != functions_.end() ) + (dynamic_cast(this)->*(i->second))( m, remoteEndpoint ); + } + +private: + struct cstr_compare{ + bool operator()( const char *lhs, const char *rhs ) const + { return std::strcmp( lhs, rhs ) < 0; } + }; + + typedef std::map function_map_type; + function_map_type functions_; +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */ \ No newline at end of file diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscException.h b/modules/touch/ext/libTUIO2/oscpack/osc/OscException.h new file mode 100644 index 0000000000..73981737e0 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscException.h @@ -0,0 +1,62 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H +#define INCLUDED_OSCPACK_OSCEXCEPTION_H + +#include + +namespace osc{ + +class Exception : public std::exception { + const char *what_; + +public: + Exception() throw() {} + Exception( const Exception& src ) throw() + : std::exception( src ) + , what_( src.what_ ) {} + Exception( const char *w ) throw() + : what_( w ) {} + Exception& operator=( const Exception& src ) throw() + { what_ = src.what_; return *this; } + virtual ~Exception() throw() {} + virtual const char* what() const throw() { return what_; } +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscHostEndianness.h b/modules/touch/ext/libTUIO2/oscpack/osc/OscHostEndianness.h new file mode 100644 index 0000000000..4682c473a5 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscHostEndianness.h @@ -0,0 +1,127 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H +#define INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H + +/* + Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined + + We try to use preprocessor symbols to deduce the host endianness. + + Alternatively you can define one of the above symbols from the command line. + Usually you do this with the -D flag to the compiler. e.g.: + + $ g++ -DOSC_HOST_LITTLE_ENDIAN ... +*/ + +#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN) + +// endianness defined on the command line. nothing to do here. + +#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE) + +// assume that __WIN32__ is only defined on little endian systems + +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN + +#elif defined(__APPLE__) + +#if defined(__LITTLE_ENDIAN__) + +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN + +#elif defined(__BIG_ENDIAN__) + +#define OSC_HOST_BIG_ENDIAN 1 +#undef OSC_HOST_LITTLE_ENDIAN + +#endif + +#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) + +// should cover gcc and clang + +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN + +#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + +#define OSC_HOST_BIG_ENDIAN 1 +#undef OSC_HOST_LITTLE_ENDIAN + +#endif + +#else + +// gcc defines __LITTLE_ENDIAN__ and __BIG_ENDIAN__ +// for others used here see http://sourceforge.net/p/predef/wiki/Endianness/ +#if (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \ + || (defined(__ARMEL__) && !defined(__ARMEB__)) \ + || (defined(__AARCH64EL__) && !defined(__AARCH64EB__)) \ + || (defined(_MIPSEL) && !defined(_MIPSEB)) \ + || (defined(__MIPSEL) && !defined(__MIPSEB)) \ + || (defined(__MIPSEL__) && !defined(__MIPSEB__)) + +#define OSC_HOST_LITTLE_ENDIAN 1 +#undef OSC_HOST_BIG_ENDIAN + +#elif (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \ + || (defined(__ARMEB__) && !defined(__ARMEL__)) \ + || (defined(__AARCH64EB__) && !defined(__AARCH64EL__)) \ + || (defined(_MIPSEB) && !defined(_MIPSEL)) \ + || (defined(__MIPSEB) && !defined(__MIPSEL)) \ + || (defined(__MIPSEB__) && !defined(__MIPSEL__)) + +#define OSC_HOST_BIG_ENDIAN 1 +#undef OSC_HOST_LITTLE_ENDIAN + +#endif + +#endif + +#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN) + +#error please edit OSCHostEndianness.h or define one of {OSC_HOST_LITTLE_ENDIAN, OSC_HOST_BIG_ENDIAN} to configure endianness + +#endif + +#endif /* INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H */ + diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.cpp b/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.cpp new file mode 100644 index 0000000000..b474b4f01a --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.cpp @@ -0,0 +1,683 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "OscOutboundPacketStream.h" + +#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) +#include // for alloca +#else +//#include // alloca on Linux (also OSX) +#include // alloca on OSX and FreeBSD (and Linux?) +#endif + +#include +#include // memcpy, memmove, strcpy, strlen +#include // ptrdiff_t + +#include "OscHostEndianness.h" + +#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug +namespace std { +using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. +} +#endif + +namespace osc{ + +static void FromInt32( char *p, int32 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::int32 i; + char c[4]; + } u; + + u.i = x; + + p[3] = u.c[0]; + p[2] = u.c[1]; + p[1] = u.c[2]; + p[0] = u.c[3]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +static void FromUInt32( char *p, uint32 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::uint32 i; + char c[4]; + } u; + + u.i = x; + + p[3] = u.c[0]; + p[2] = u.c[1]; + p[1] = u.c[2]; + p[0] = u.c[3]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +static void FromInt64( char *p, int64 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::int64 i; + char c[8]; + } u; + + u.i = x; + + p[7] = u.c[0]; + p[6] = u.c[1]; + p[5] = u.c[2]; + p[4] = u.c[3]; + p[3] = u.c[4]; + p[2] = u.c[5]; + p[1] = u.c[6]; + p[0] = u.c[7]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +static void FromUInt64( char *p, uint64 x ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::uint64 i; + char c[8]; + } u; + + u.i = x; + + p[7] = u.c[0]; + p[6] = u.c[1]; + p[5] = u.c[2]; + p[4] = u.c[3]; + p[3] = u.c[4]; + p[2] = u.c[5]; + p[1] = u.c[6]; + p[0] = u.c[7]; +#else + *reinterpret_cast(p) = x; +#endif +} + + +// round up to the next highest multiple of 4. unless x is already a multiple of 4 +static inline std::size_t RoundUp4( std::size_t x ) +{ + return (x + 3) & ~((std::size_t)0x03); +} + + +OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity ) + : data_( buffer ) + , end_( data_ + capacity ) + , typeTagsCurrent_( end_ ) + , messageCursor_( data_ ) + , argumentCurrent_( data_ ) + , elementSizePtr_( 0 ) + , messageIsInProgress_( false ) +{ + // sanity check integer types declared in OscTypes.h + // you'll need to fix OscTypes.h if any of these asserts fail + assert( sizeof(osc::int32) == 4 ); + assert( sizeof(osc::uint32) == 4 ); + assert( sizeof(osc::int64) == 8 ); + assert( sizeof(osc::uint64) == 8 ); +} + + +OutboundPacketStream::~OutboundPacketStream() +{ + +} + + +char *OutboundPacketStream::BeginElement( char *beginPtr ) +{ + if( elementSizePtr_ == 0 ){ + + elementSizePtr_ = reinterpret_cast(data_); + + return beginPtr; + + }else{ + // store an offset to the old element size ptr in the element size slot + // we store an offset rather than the actual pointer to be 64 bit clean. + *reinterpret_cast(beginPtr) = + (uint32)(reinterpret_cast(elementSizePtr_) - data_); + + elementSizePtr_ = reinterpret_cast(beginPtr); + + return beginPtr + 4; + } +} + + +void OutboundPacketStream::EndElement( char *endPtr ) +{ + assert( elementSizePtr_ != 0 ); + + if( elementSizePtr_ == reinterpret_cast(data_) ){ + + elementSizePtr_ = 0; + + }else{ + // while building an element, an offset to the containing element's + // size slot is stored in the elements size slot (or a ptr to data_ + // if there is no containing element). We retrieve that here + uint32 *previousElementSizePtr = + reinterpret_cast(data_ + *elementSizePtr_); + + // then we store the element size in the slot. note that the element + // size does not include the size slot, hence the - 4 below. + + std::ptrdiff_t d = endPtr - reinterpret_cast(elementSizePtr_); + // assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb + + uint32 elementSize = static_cast(d - 4); + FromUInt32( reinterpret_cast(elementSizePtr_), elementSize ); + + // finally, we reset the element size ptr to the containing element + elementSizePtr_ = previousElementSizePtr; + } +} + + +bool OutboundPacketStream::ElementSizeSlotRequired() const +{ + return (elementSizePtr_ != 0); +} + + +void OutboundPacketStream::CheckForAvailableBundleSpace() +{ + std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; + + if( required > Capacity() ) + throw OutOfBufferMemoryException(); +} + + +void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) +{ + // plus 4 for at least four bytes of type tag + std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + + RoundUp4(std::strlen(addressPattern) + 1) + 4; + + if( required > Capacity() ) + throw OutOfBufferMemoryException(); +} + + +void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength ) +{ + // plus three for extra type tag, comma and null terminator + std::size_t required = (argumentCurrent_ - data_) + argumentLength + + RoundUp4( (end_ - typeTagsCurrent_) + 3 ); + + if( required > Capacity() ) + throw OutOfBufferMemoryException(); +} + + +void OutboundPacketStream::Clear() +{ + typeTagsCurrent_ = end_; + messageCursor_ = data_; + argumentCurrent_ = data_; + elementSizePtr_ = 0; + messageIsInProgress_ = false; +} + + +std::size_t OutboundPacketStream::Capacity() const +{ + return end_ - data_; +} + + +std::size_t OutboundPacketStream::Size() const +{ + std::size_t result = argumentCurrent_ - data_; + if( IsMessageInProgress() ){ + // account for the length of the type tag string. the total type tag + // includes an initial comma, plus at least one terminating \0 + result += RoundUp4( (end_ - typeTagsCurrent_) + 2 ); + } + + return result; +} + + +const char *OutboundPacketStream::Data() const +{ + return data_; +} + + +bool OutboundPacketStream::IsReady() const +{ + return (!IsMessageInProgress() && !IsBundleInProgress()); +} + + +bool OutboundPacketStream::IsMessageInProgress() const +{ + return messageIsInProgress_; +} + + +bool OutboundPacketStream::IsBundleInProgress() const +{ + return (elementSizePtr_ != 0); +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs ) +{ + if( IsMessageInProgress() ) + throw MessageInProgressException(); + + CheckForAvailableBundleSpace(); + + messageCursor_ = BeginElement( messageCursor_ ); + + std::memcpy( messageCursor_, "#bundle\0", 8 ); + FromUInt64( messageCursor_ + 8, rhs.timeTag ); + + messageCursor_ += 16; + argumentCurrent_ = messageCursor_; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs ) +{ + (void) rhs; + + if( !IsBundleInProgress() ) + throw BundleNotInProgressException(); + if( IsMessageInProgress() ) + throw MessageInProgressException(); + + EndElement( messageCursor_ ); + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs ) +{ + if( IsMessageInProgress() ) + throw MessageInProgressException(); + + CheckForAvailableMessageSpace( rhs.addressPattern ); + + messageCursor_ = BeginElement( messageCursor_ ); + + std::strcpy( messageCursor_, rhs.addressPattern ); + std::size_t rhsLength = std::strlen(rhs.addressPattern); + messageCursor_ += rhsLength + 1; + + // zero pad to 4-byte boundary + std::size_t i = rhsLength + 1; + while( i & 0x3 ){ + *messageCursor_++ = '\0'; + ++i; + } + + argumentCurrent_ = messageCursor_; + typeTagsCurrent_ = end_; + + messageIsInProgress_ = true; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs ) +{ + (void) rhs; + + if( !IsMessageInProgress() ) + throw MessageNotInProgressException(); + + std::size_t typeTagsCount = end_ - typeTagsCurrent_; + + if( typeTagsCount ){ + + char *tempTypeTags = (char*)alloca(typeTagsCount); + std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); + + // slot size includes comma and null terminator + std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); + + std::size_t argumentsSize = argumentCurrent_ - messageCursor_; + + std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); + + messageCursor_[0] = ','; + // copy type tags in reverse (really forward) order + for( std::size_t i=0; i < typeTagsCount; ++i ) + messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; + + char *p = messageCursor_ + 1 + typeTagsCount; + for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) + *p++ = '\0'; + + typeTagsCurrent_ = end_; + + // advance messageCursor_ for next message + messageCursor_ += typeTagSlotSize + argumentsSize; + + }else{ + // send an empty type tags string + std::memcpy( messageCursor_, ",\0\0\0", 4 ); + + // advance messageCursor_ for next message + messageCursor_ += 4; + } + + argumentCurrent_ = messageCursor_; + + EndElement( messageCursor_ ); + + messageIsInProgress_ = false; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) +{ + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG); + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = NIL_TYPE_TAG; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = INT32_TYPE_TAG; + FromInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = FLOAT_TYPE_TAG; + +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + float f; + char c[4]; + } u; + + u.f = rhs; + + argumentCurrent_[3] = u.c[0]; + argumentCurrent_[2] = u.c[1]; + argumentCurrent_[1] = u.c[2]; + argumentCurrent_[0] = u.c[3]; +#else + *reinterpret_cast(argumentCurrent_) = rhs; +#endif + + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = CHAR_TYPE_TAG; + FromInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG; + FromUInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) +{ + CheckForAvailableArgumentSpace(4); + + *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG; + FromUInt32( argumentCurrent_, rhs ); + argumentCurrent_ += 4; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) +{ + CheckForAvailableArgumentSpace(8); + + *(--typeTagsCurrent_) = INT64_TYPE_TAG; + FromInt64( argumentCurrent_, rhs ); + argumentCurrent_ += 8; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) +{ + CheckForAvailableArgumentSpace(8); + + *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG; + FromUInt64( argumentCurrent_, rhs ); + argumentCurrent_ += 8; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) +{ + CheckForAvailableArgumentSpace(8); + + *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG; + +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + double f; + char c[8]; + } u; + + u.f = rhs; + + argumentCurrent_[7] = u.c[0]; + argumentCurrent_[6] = u.c[1]; + argumentCurrent_[5] = u.c[2]; + argumentCurrent_[4] = u.c[3]; + argumentCurrent_[3] = u.c[4]; + argumentCurrent_[2] = u.c[5]; + argumentCurrent_[1] = u.c[6]; + argumentCurrent_[0] = u.c[7]; +#else + *reinterpret_cast(argumentCurrent_) = rhs; +#endif + + argumentCurrent_ += 8; + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) +{ + CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); + + *(--typeTagsCurrent_) = STRING_TYPE_TAG; + std::strcpy( argumentCurrent_, rhs ); + std::size_t rhsLength = std::strlen(rhs); + argumentCurrent_ += rhsLength + 1; + + // zero pad to 4-byte boundary + std::size_t i = rhsLength + 1; + while( i & 0x3 ){ + *argumentCurrent_++ = '\0'; + ++i; + } + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) +{ + CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); + + *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; + std::strcpy( argumentCurrent_, rhs ); + std::size_t rhsLength = std::strlen(rhs); + argumentCurrent_ += rhsLength + 1; + + // zero pad to 4-byte boundary + std::size_t i = rhsLength + 1; + while( i & 0x3 ){ + *argumentCurrent_++ = '\0'; + ++i; + } + + return *this; +} + + +OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) +{ + CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) ); + + *(--typeTagsCurrent_) = BLOB_TYPE_TAG; + FromUInt32( argumentCurrent_, rhs.size ); + argumentCurrent_ += 4; + + std::memcpy( argumentCurrent_, rhs.data, rhs.size ); + argumentCurrent_ += rhs.size; + + // zero pad to 4-byte boundary + unsigned long i = rhs.size; + while( i & 0x3 ){ + *argumentCurrent_++ = '\0'; + ++i; + } + + return *this; +} + +OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG; + + return *this; +} + +OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs ) +{ + (void) rhs; + CheckForAvailableArgumentSpace(0); + + *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG; + + return *this; +} + +} // namespace osc + + diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.h b/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.h new file mode 100644 index 0000000000..1a90a01239 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.h @@ -0,0 +1,154 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H +#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H + +#include // size_t + +#include "OscTypes.h" +#include "OscException.h" + + +namespace osc{ + +class OutOfBufferMemoryException : public Exception{ +public: + OutOfBufferMemoryException( const char *w="out of buffer memory" ) + : Exception( w ) {} +}; + +class BundleNotInProgressException : public Exception{ +public: + BundleNotInProgressException( + const char *w="call to EndBundle when bundle is not in progress" ) + : Exception( w ) {} +}; + +class MessageInProgressException : public Exception{ +public: + MessageInProgressException( + const char *w="opening or closing bundle or message while message is in progress" ) + : Exception( w ) {} +}; + +class MessageNotInProgressException : public Exception{ +public: + MessageNotInProgressException( + const char *w="call to EndMessage when message is not in progress" ) + : Exception( w ) {} +}; + + +class OutboundPacketStream{ +public: + OutboundPacketStream( char *buffer, std::size_t capacity ); + ~OutboundPacketStream(); + + void Clear(); + + std::size_t Capacity() const; + + // invariant: size() is valid even while building a message. + std::size_t Size() const; + + const char *Data() const; + + // indicates that all messages have been closed with a matching EndMessage + // and all bundles have been closed with a matching EndBundle + bool IsReady() const; + + bool IsMessageInProgress() const; + bool IsBundleInProgress() const; + + OutboundPacketStream& operator<<( const BundleInitiator& rhs ); + OutboundPacketStream& operator<<( const BundleTerminator& rhs ); + + OutboundPacketStream& operator<<( const BeginMessage& rhs ); + OutboundPacketStream& operator<<( const MessageTerminator& rhs ); + + OutboundPacketStream& operator<<( bool rhs ); + OutboundPacketStream& operator<<( const NilType& rhs ); + OutboundPacketStream& operator<<( const InfinitumType& rhs ); + OutboundPacketStream& operator<<( int32 rhs ); + +#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)) + OutboundPacketStream& operator<<( int rhs ) + { *this << (int32)rhs; return *this; } +#endif + + OutboundPacketStream& operator<<( float rhs ); + OutboundPacketStream& operator<<( char rhs ); + OutboundPacketStream& operator<<( const RgbaColor& rhs ); + OutboundPacketStream& operator<<( const MidiMessage& rhs ); + OutboundPacketStream& operator<<( int64 rhs ); + OutboundPacketStream& operator<<( const TimeTag& rhs ); + OutboundPacketStream& operator<<( double rhs ); + OutboundPacketStream& operator<<( const char* rhs ); + OutboundPacketStream& operator<<( const Symbol& rhs ); + OutboundPacketStream& operator<<( const Blob& rhs ); + + OutboundPacketStream& operator<<( const ArrayInitiator& rhs ); + OutboundPacketStream& operator<<( const ArrayTerminator& rhs ); + +private: + + char *BeginElement( char *beginPtr ); + void EndElement( char *endPtr ); + + bool ElementSizeSlotRequired() const; + void CheckForAvailableBundleSpace(); + void CheckForAvailableMessageSpace( const char *addressPattern ); + void CheckForAvailableArgumentSpace( std::size_t argumentLength ); + + char *data_; + char *end_; + + char *typeTagsCurrent_; // stored in reverse order + char *messageCursor_; + char *argumentCurrent_; + + // elementSizePtr_ has two special values: 0 indicates that a bundle + // isn't open, and elementSizePtr_==data_ indicates that a bundle is + // open but that it doesn't have a size slot (ie the outermost bundle) + uint32 *elementSizePtr_; + + bool messageIsInProgress_; +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscPacketListener.h b/modules/touch/ext/libTUIO2/oscpack/osc/OscPacketListener.h new file mode 100644 index 0000000000..472cb1066f --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscPacketListener.h @@ -0,0 +1,79 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCPACKETLISTENER_H +#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H + +#include "OscReceivedElements.h" +#include "../ip/PacketListener.h" + + +namespace osc{ + +class OscPacketListener : public PacketListener{ +protected: + virtual void ProcessBundle( const osc::ReceivedBundle& b, + const IpEndpointName& remoteEndpoint ) + { + // ignore bundle time tag for now + + for( ReceivedBundle::const_iterator i = b.ElementsBegin(); + i != b.ElementsEnd(); ++i ){ + if( i->IsBundle() ) + ProcessBundle( ReceivedBundle(*i), remoteEndpoint ); + else + ProcessMessage( ReceivedMessage(*i), remoteEndpoint ); + } + } + + virtual void ProcessMessage( const osc::ReceivedMessage& m, + const IpEndpointName& remoteEndpoint ) = 0; + +public: + virtual void ProcessPacket( const char *data, int size, + const IpEndpointName& remoteEndpoint ) + { + osc::ReceivedPacket p( data, size ); + if( p.IsBundle() ) + ProcessBundle( ReceivedBundle(p), remoteEndpoint ); + else + ProcessMessage( ReceivedMessage(p), remoteEndpoint ); + } +}; + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.cpp b/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.cpp new file mode 100644 index 0000000000..bc1689bc1d --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.cpp @@ -0,0 +1,261 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "OscPrintReceivedElements.h" + +#include +#include +#include +#include + +#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug +namespace std { +using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. +} +#endif + +namespace osc{ + + +std::ostream& operator<<( std::ostream & os, + const ReceivedMessageArgument& arg ) +{ + switch( arg.TypeTag() ){ + case TRUE_TYPE_TAG: + os << "bool:true"; + break; + + case FALSE_TYPE_TAG: + os << "bool:false"; + break; + + case NIL_TYPE_TAG: + os << "(Nil)"; + break; + + case INFINITUM_TYPE_TAG: + os << "(Infinitum)"; + break; + + case INT32_TYPE_TAG: + os << "int32:" << arg.AsInt32Unchecked(); + break; + + case FLOAT_TYPE_TAG: + os << "float32:" << arg.AsFloatUnchecked(); + break; + + case CHAR_TYPE_TAG: + { + char s[2] = {0}; + s[0] = arg.AsCharUnchecked(); + os << "char:'" << s << "'"; + } + break; + + case RGBA_COLOR_TYPE_TAG: + { + uint32 color = arg.AsRgbaColorUnchecked(); + + os << "RGBA:0x" + << std::hex << std::setfill('0') + << std::setw(2) << (int)((color>>24) & 0xFF) + << std::setw(2) << (int)((color>>16) & 0xFF) + << std::setw(2) << (int)((color>>8) & 0xFF) + << std::setw(2) << (int)(color & 0xFF) + << std::setfill(' '); + os.unsetf(std::ios::basefield); + } + break; + + case MIDI_MESSAGE_TYPE_TAG: + { + uint32 m = arg.AsMidiMessageUnchecked(); + os << "midi (port, status, data1, data2):<<" + << std::hex << std::setfill('0') + << "0x" << std::setw(2) << (int)((m>>24) & 0xFF) + << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF) + << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF) + << " 0x" << std::setw(2) << (int)(m & 0xFF) + << std::setfill(' ') << ">>"; + os.unsetf(std::ios::basefield); + } + break; + + case INT64_TYPE_TAG: + os << "int64:" << arg.AsInt64Unchecked(); + break; + + case TIME_TAG_TYPE_TAG: + { + os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " "; + + std::time_t t = + (unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); + + const char *timeString = std::ctime( &t ); + size_t len = std::strlen( timeString ); + + // -1 to omit trailing newline from string returned by ctime() + if( len > 1 ) + os.write( timeString, len - 1 ); + } + break; + + case DOUBLE_TYPE_TAG: + os << "double:" << arg.AsDoubleUnchecked(); + break; + + case STRING_TYPE_TAG: + os << "OSC-string:`" << arg.AsStringUnchecked() << "'"; + break; + + case SYMBOL_TYPE_TAG: + os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'"; + break; + + case BLOB_TYPE_TAG: + { + const void *data; + osc_bundle_element_size_t size; + arg.AsBlobUnchecked( data, size ); + os << "OSC-blob:<<" << std::hex << std::setfill('0'); + unsigned char *p = (unsigned char*)data; + for( osc_bundle_element_size_t i = 0; i < size; ++i ){ + os << "0x" << std::setw(2) << int(p[i]); + if( i != size-1 ) + os << ' '; + } + os.unsetf(std::ios::basefield); + os << ">>" << std::setfill(' '); + } + break; + + case ARRAY_BEGIN_TYPE_TAG: + os << "["; + break; + + case ARRAY_END_TYPE_TAG: + os << "]"; + break; + + default: + os << "unknown"; + } + + return os; +} + + +std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ) +{ + os << "["; + if( m.AddressPatternIsUInt32() ) + os << m.AddressPatternAsUInt32(); + else + os << m.AddressPattern(); + + bool first = true; + for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); + i != m.ArgumentsEnd(); ++i ){ + if( first ){ + os << " "; + first = false; + }else{ + os << ", "; + } + + os << *i; + } + + os << "]"; + + return os; +} + + +std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ) +{ + static int indent = 0; + + for( int j=0; j < indent; ++j ) + os << " "; + os << "{ ( "; + if( b.TimeTag() == 1 ) + os << "immediate"; + else + os << b.TimeTag(); + os << " )\n"; + + ++indent; + + for( ReceivedBundle::const_iterator i = b.ElementsBegin(); + i != b.ElementsEnd(); ++i ){ + if( i->IsBundle() ){ + ReceivedBundle b(*i); + os << b << "\n"; + }else{ + ReceivedMessage m(*i); + for( int j=0; j < indent; ++j ) + os << " "; + os << m << "\n"; + } + } + + --indent; + + for( int j=0; j < indent; ++j ) + os << " "; + os << "}"; + + return os; +} + + +std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ) +{ + if( p.IsBundle() ){ + ReceivedBundle b(p); + os << b << "\n"; + }else{ + ReceivedMessage m(p); + os << m << "\n"; + } + + return os; +} + +} // namespace osc diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.h b/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.h new file mode 100644 index 0000000000..8d71391f0c --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.h @@ -0,0 +1,54 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H +#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H + +#include + +#include "OscReceivedElements.h" + + +namespace osc{ + +std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ); +std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg ); +std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ); +std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ); + +} // namespace osc + +#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.cpp b/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.cpp new file mode 100644 index 0000000000..14bbe39c19 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.cpp @@ -0,0 +1,796 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "OscReceivedElements.h" + +#include "OscHostEndianness.h" + +#include // ptrdiff_t + +namespace osc{ + + +// return the first 4 byte boundary after the end of a str4 +// be careful about calling this version if you don't know whether +// the string is terminated correctly. +static inline const char* FindStr4End( const char *p ) +{ + if( p[0] == '\0' ) // special case for SuperCollider integer address pattern + return p + 4; + + p += 3; + + while( *p ) + p += 4; + + return p + 1; +} + + +// return the first 4 byte boundary after the end of a str4 +// returns 0 if p == end or if the string is unterminated +static inline const char* FindStr4End( const char *p, const char *end ) +{ + if( p >= end ) + return 0; + + if( p[0] == '\0' ) // special case for SuperCollider integer address pattern + return p + 4; + + p += 3; + end -= 1; + + while( p < end && *p ) + p += 4; + + if( *p ) + return 0; + else + return p + 1; +} + + +// round up to the next highest multiple of 4. unless x is already a multiple of 4 +static inline uint32 RoundUp4( uint32 x ) +{ + return (x + 3) & ~((uint32)0x03); +} + + +static inline int32 ToInt32( const char *p ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::int32 i; + char c[4]; + } u; + + u.c[0] = p[3]; + u.c[1] = p[2]; + u.c[2] = p[1]; + u.c[3] = p[0]; + + return u.i; +#else + return *(int32*)p; +#endif +} + + +static inline uint32 ToUInt32( const char *p ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::uint32 i; + char c[4]; + } u; + + u.c[0] = p[3]; + u.c[1] = p[2]; + u.c[2] = p[1]; + u.c[3] = p[0]; + + return u.i; +#else + return *(uint32*)p; +#endif +} + + +static inline int64 ToInt64( const char *p ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::int64 i; + char c[8]; + } u; + + u.c[0] = p[7]; + u.c[1] = p[6]; + u.c[2] = p[5]; + u.c[3] = p[4]; + u.c[4] = p[3]; + u.c[5] = p[2]; + u.c[6] = p[1]; + u.c[7] = p[0]; + + return u.i; +#else + return *(int64*)p; +#endif +} + + +static inline uint64 ToUInt64( const char *p ) +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::uint64 i; + char c[8]; + } u; + + u.c[0] = p[7]; + u.c[1] = p[6]; + u.c[2] = p[5]; + u.c[3] = p[4]; + u.c[4] = p[3]; + u.c[5] = p[2]; + u.c[6] = p[1]; + u.c[7] = p[0]; + + return u.i; +#else + return *(uint64*)p; +#endif +} + +//------------------------------------------------------------------------------ + +bool ReceivedPacket::IsBundle() const +{ + return (Size() > 0 && Contents()[0] == '#'); +} + +//------------------------------------------------------------------------------ + +bool ReceivedBundleElement::IsBundle() const +{ + return (Size() > 0 && Contents()[0] == '#'); +} + + +osc_bundle_element_size_t ReceivedBundleElement::Size() const +{ + return ToInt32( sizePtr_ ); +} + +//------------------------------------------------------------------------------ + +bool ReceivedMessageArgument::AsBool() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == TRUE_TYPE_TAG ) + return true; + else if( *typeTagPtr_ == FALSE_TYPE_TAG ) + return false; + else + throw WrongArgumentTypeException(); +} + + +bool ReceivedMessageArgument::AsBoolUnchecked() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == TRUE_TYPE_TAG ) + return true; + else + return false; +} + + +int32 ReceivedMessageArgument::AsInt32() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == INT32_TYPE_TAG ) + return AsInt32Unchecked(); + else + throw WrongArgumentTypeException(); +} + + +int32 ReceivedMessageArgument::AsInt32Unchecked() const +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + osc::int32 i; + char c[4]; + } u; + + u.c[0] = argumentPtr_[3]; + u.c[1] = argumentPtr_[2]; + u.c[2] = argumentPtr_[1]; + u.c[3] = argumentPtr_[0]; + + return u.i; +#else + return *(int32*)argumentPtr_; +#endif +} + + +float ReceivedMessageArgument::AsFloat() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == FLOAT_TYPE_TAG ) + return AsFloatUnchecked(); + else + throw WrongArgumentTypeException(); +} + + +float ReceivedMessageArgument::AsFloatUnchecked() const +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + float f; + char c[4]; + } u; + + u.c[0] = argumentPtr_[3]; + u.c[1] = argumentPtr_[2]; + u.c[2] = argumentPtr_[1]; + u.c[3] = argumentPtr_[0]; + + return u.f; +#else + return *(float*)argumentPtr_; +#endif +} + + +char ReceivedMessageArgument::AsChar() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == CHAR_TYPE_TAG ) + return AsCharUnchecked(); + else + throw WrongArgumentTypeException(); +} + + +char ReceivedMessageArgument::AsCharUnchecked() const +{ + return (char)ToInt32( argumentPtr_ ); +} + + +uint32 ReceivedMessageArgument::AsRgbaColor() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG ) + return AsRgbaColorUnchecked(); + else + throw WrongArgumentTypeException(); +} + + +uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const +{ + return ToUInt32( argumentPtr_ ); +} + + +uint32 ReceivedMessageArgument::AsMidiMessage() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG ) + return AsMidiMessageUnchecked(); + else + throw WrongArgumentTypeException(); +} + + +uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const +{ + return ToUInt32( argumentPtr_ ); +} + + +int64 ReceivedMessageArgument::AsInt64() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == INT64_TYPE_TAG ) + return AsInt64Unchecked(); + else + throw WrongArgumentTypeException(); +} + + +int64 ReceivedMessageArgument::AsInt64Unchecked() const +{ + return ToInt64( argumentPtr_ ); +} + + +uint64 ReceivedMessageArgument::AsTimeTag() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG ) + return AsTimeTagUnchecked(); + else + throw WrongArgumentTypeException(); +} + + +uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const +{ + return ToUInt64( argumentPtr_ ); +} + + +double ReceivedMessageArgument::AsDouble() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == DOUBLE_TYPE_TAG ) + return AsDoubleUnchecked(); + else + throw WrongArgumentTypeException(); +} + + +double ReceivedMessageArgument::AsDoubleUnchecked() const +{ +#ifdef OSC_HOST_LITTLE_ENDIAN + union{ + double d; + char c[8]; + } u; + + u.c[0] = argumentPtr_[7]; + u.c[1] = argumentPtr_[6]; + u.c[2] = argumentPtr_[5]; + u.c[3] = argumentPtr_[4]; + u.c[4] = argumentPtr_[3]; + u.c[5] = argumentPtr_[2]; + u.c[6] = argumentPtr_[1]; + u.c[7] = argumentPtr_[0]; + + return u.d; +#else + return *(double*)argumentPtr_; +#endif +} + + +const char* ReceivedMessageArgument::AsString() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == STRING_TYPE_TAG ) + return argumentPtr_; + else + throw WrongArgumentTypeException(); +} + + +const char* ReceivedMessageArgument::AsSymbol() const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == SYMBOL_TYPE_TAG ) + return argumentPtr_; + else + throw WrongArgumentTypeException(); +} + + +void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size ) const +{ + if( !typeTagPtr_ ) + throw MissingArgumentException(); + else if( *typeTagPtr_ == BLOB_TYPE_TAG ) + AsBlobUnchecked( data, size ); + else + throw WrongArgumentTypeException(); +} + + +void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const +{ + // read blob size as an unsigned int then validate + osc_bundle_element_size_t sizeResult = (osc_bundle_element_size_t)ToUInt32( argumentPtr_ ); + if( !IsValidElementSizeValue(sizeResult) ) + throw MalformedMessageException("invalid blob size"); + + size = sizeResult; + data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32); +} + +std::size_t ReceivedMessageArgument::ComputeArrayItemCount() const +{ + // it is only valid to call ComputeArrayItemCount when the argument is the array start marker + if( !IsArrayBegin() ) + throw WrongArgumentTypeException(); + + std::size_t result = 0; + unsigned int level = 0; + const char *typeTag = typeTagPtr_ + 1; + + // iterate through all type tags. note that ReceivedMessage::Init + // has already checked that the message is well formed. + while( *typeTag ) { + switch( *typeTag++ ) { + case ARRAY_BEGIN_TYPE_TAG: + level += 1; + break; + + case ARRAY_END_TYPE_TAG: + if(level == 0) + return result; + level -= 1; + break; + + default: + if( level == 0 ) // only count items at level 0 + ++result; + } + } + + return result; +} + +//------------------------------------------------------------------------------ + +void ReceivedMessageArgumentIterator::Advance() +{ + if( !value_.typeTagPtr_ ) + return; + + switch( *value_.typeTagPtr_++ ){ + case '\0': + // don't advance past end + --value_.typeTagPtr_; + break; + + case TRUE_TYPE_TAG: + case FALSE_TYPE_TAG: + case NIL_TYPE_TAG: + case INFINITUM_TYPE_TAG: + + // zero length + break; + + case INT32_TYPE_TAG: + case FLOAT_TYPE_TAG: + case CHAR_TYPE_TAG: + case RGBA_COLOR_TYPE_TAG: + case MIDI_MESSAGE_TYPE_TAG: + + value_.argumentPtr_ += 4; + break; + + case INT64_TYPE_TAG: + case TIME_TAG_TYPE_TAG: + case DOUBLE_TYPE_TAG: + + value_.argumentPtr_ += 8; + break; + + case STRING_TYPE_TAG: + case SYMBOL_TYPE_TAG: + + // we use the unsafe function FindStr4End(char*) here because all of + // the arguments have already been validated in + // ReceivedMessage::Init() below. + + value_.argumentPtr_ = FindStr4End( value_.argumentPtr_ ); + break; + + case BLOB_TYPE_TAG: + { + // treat blob size as an unsigned int for the purposes of this calculation + uint32 blobSize = ToUInt32( value_.argumentPtr_ ); + value_.argumentPtr_ = value_.argumentPtr_ + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize ); + } + break; + + case ARRAY_BEGIN_TYPE_TAG: + case ARRAY_END_TYPE_TAG: + + // [ Indicates the beginning of an array. The tags following are for + // data in the Array until a close brace tag is reached. + // ] Indicates the end of an array. + + // zero length, don't advance argument ptr + break; + + default: // unknown type tag + // don't advance + --value_.typeTagPtr_; + break; + } +} + +//------------------------------------------------------------------------------ + +ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet ) + : addressPattern_( packet.Contents() ) +{ + Init( packet.Contents(), packet.Size() ); +} + + +ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement ) + : addressPattern_( bundleElement.Contents() ) +{ + Init( bundleElement.Contents(), bundleElement.Size() ); +} + + +bool ReceivedMessage::AddressPatternIsUInt32() const +{ + return (addressPattern_[0] == '\0'); +} + + +uint32 ReceivedMessage::AddressPatternAsUInt32() const +{ + return ToUInt32( addressPattern_ ); +} + + +void ReceivedMessage::Init( const char *message, osc_bundle_element_size_t size ) +{ + if( !IsValidElementSizeValue(size) ) + throw MalformedMessageException( "invalid message size" ); + + if( size == 0 ) + throw MalformedMessageException( "zero length messages not permitted" ); + + if( !IsMultipleOf4(size) ) + throw MalformedMessageException( "message size must be multiple of four" ); + + const char *end = message + size; + + typeTagsBegin_ = FindStr4End( addressPattern_, end ); + if( typeTagsBegin_ == 0 ){ + // address pattern was not terminated before end + throw MalformedMessageException( "unterminated address pattern" ); + } + + if( typeTagsBegin_ == end ){ + // message consists of only the address pattern - no arguments or type tags. + typeTagsBegin_ = 0; + typeTagsEnd_ = 0; + arguments_ = 0; + + }else{ + if( *typeTagsBegin_ != ',' ) + throw MalformedMessageException( "type tags not present" ); + + if( *(typeTagsBegin_ + 1) == '\0' ){ + // zero length type tags + typeTagsBegin_ = 0; + typeTagsEnd_ = 0; + arguments_ = 0; + + }else{ + // check that all arguments are present and well formed + + arguments_ = FindStr4End( typeTagsBegin_, end ); + if( arguments_ == 0 ){ + throw MalformedMessageException( "type tags were not terminated before end of message" ); + } + + ++typeTagsBegin_; // advance past initial ',' + + const char *typeTag = typeTagsBegin_; + const char *argument = arguments_; + unsigned int arrayLevel = 0; + + do{ + switch( *typeTag ){ + case TRUE_TYPE_TAG: + case FALSE_TYPE_TAG: + case NIL_TYPE_TAG: + case INFINITUM_TYPE_TAG: + // zero length + break; + + // [ Indicates the beginning of an array. The tags following are for + // data in the Array until a close brace tag is reached. + // ] Indicates the end of an array. + case ARRAY_BEGIN_TYPE_TAG: + ++arrayLevel; + // (zero length argument data) + break; + + case ARRAY_END_TYPE_TAG: + --arrayLevel; + // (zero length argument data) + break; + + case INT32_TYPE_TAG: + case FLOAT_TYPE_TAG: + case CHAR_TYPE_TAG: + case RGBA_COLOR_TYPE_TAG: + case MIDI_MESSAGE_TYPE_TAG: + + if( argument == end ) + throw MalformedMessageException( "arguments exceed message size" ); + argument += 4; + if( argument > end ) + throw MalformedMessageException( "arguments exceed message size" ); + break; + + case INT64_TYPE_TAG: + case TIME_TAG_TYPE_TAG: + case DOUBLE_TYPE_TAG: + + if( argument == end ) + throw MalformedMessageException( "arguments exceed message size" ); + argument += 8; + if( argument > end ) + throw MalformedMessageException( "arguments exceed message size" ); + break; + + case STRING_TYPE_TAG: + case SYMBOL_TYPE_TAG: + + if( argument == end ) + throw MalformedMessageException( "arguments exceed message size" ); + argument = FindStr4End( argument, end ); + if( argument == 0 ) + throw MalformedMessageException( "unterminated string argument" ); + break; + + case BLOB_TYPE_TAG: + { + if( argument + osc::OSC_SIZEOF_INT32 > end ) + MalformedMessageException( "arguments exceed message size" ); + + // treat blob size as an unsigned int for the purposes of this calculation + uint32 blobSize = ToUInt32( argument ); + argument = argument + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize ); + if( argument > end ) + MalformedMessageException( "arguments exceed message size" ); + } + break; + + default: + throw MalformedMessageException( "unknown type tag" ); + } + + }while( *++typeTag != '\0' ); + typeTagsEnd_ = typeTag; + + if( arrayLevel != 0 ) + throw MalformedMessageException( "array was not terminated before end of message (expected ']' end of array tag)" ); + } + + // These invariants should be guaranteed by the above code. + // we depend on them in the implementation of ArgumentCount() +#ifndef NDEBUG + std::ptrdiff_t argumentCount = typeTagsEnd_ - typeTagsBegin_; + assert( argumentCount >= 0 ); + assert( argumentCount <= OSC_INT32_MAX ); +#endif + } +} + +//------------------------------------------------------------------------------ + +ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet ) + : elementCount_( 0 ) +{ + Init( packet.Contents(), packet.Size() ); +} + + +ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement ) + : elementCount_( 0 ) +{ + Init( bundleElement.Contents(), bundleElement.Size() ); +} + + +void ReceivedBundle::Init( const char *bundle, osc_bundle_element_size_t size ) +{ + + if( !IsValidElementSizeValue(size) ) + throw MalformedBundleException( "invalid bundle size" ); + + if( size < 16 ) + throw MalformedBundleException( "packet too short for bundle" ); + + if( !IsMultipleOf4(size) ) + throw MalformedBundleException( "bundle size must be multiple of four" ); + + if( bundle[0] != '#' + || bundle[1] != 'b' + || bundle[2] != 'u' + || bundle[3] != 'n' + || bundle[4] != 'd' + || bundle[5] != 'l' + || bundle[6] != 'e' + || bundle[7] != '\0' ) + throw MalformedBundleException( "bad bundle address pattern" ); + + end_ = bundle + size; + + timeTag_ = bundle + 8; + + const char *p = timeTag_ + 8; + + while( p < end_ ){ + if( p + osc::OSC_SIZEOF_INT32 > end_ ) + throw MalformedBundleException( "packet too short for elementSize" ); + + // treat element size as an unsigned int for the purposes of this calculation + uint32 elementSize = ToUInt32( p ); + if( (elementSize & ((uint32)0x03)) != 0 ) + throw MalformedBundleException( "bundle element size must be multiple of four" ); + + p += osc::OSC_SIZEOF_INT32 + elementSize; + if( p > end_ ) + throw MalformedBundleException( "packet too short for bundle element" ); + + ++elementCount_; + } + + if( p != end_ ) + throw MalformedBundleException( "bundle contents " ); +} + + +uint64 ReceivedBundle::TimeTag() const +{ + return ToUInt64( timeTag_ ); +} + + +} // namespace osc + diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.h b/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.h new file mode 100644 index 0000000000..69d0e6c545 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.h @@ -0,0 +1,548 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H +#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H + +#include +#include +#include // size_t + +#include "OscTypes.h" +#include "OscException.h" + + +namespace osc{ + + +class MalformedPacketException : public Exception{ +public: + MalformedPacketException( const char *w="malformed packet" ) + : Exception( w ) {} +}; + +class MalformedMessageException : public Exception{ +public: + MalformedMessageException( const char *w="malformed message" ) + : Exception( w ) {} +}; + +class MalformedBundleException : public Exception{ +public: + MalformedBundleException( const char *w="malformed bundle" ) + : Exception( w ) {} +}; + +class WrongArgumentTypeException : public Exception{ +public: + WrongArgumentTypeException( const char *w="wrong argument type" ) + : Exception( w ) {} +}; + +class MissingArgumentException : public Exception{ +public: + MissingArgumentException( const char *w="missing argument" ) + : Exception( w ) {} +}; + +class ExcessArgumentException : public Exception{ +public: + ExcessArgumentException( const char *w="too many arguments" ) + : Exception( w ) {} +}; + + +class ReceivedPacket{ +public: + // Although the OSC spec is not entirely clear on this, we only support + // packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value + // representable by an int32). An exception will be raised if you pass a + // larger value to the ReceivedPacket() constructor. + + ReceivedPacket( const char *contents, osc_bundle_element_size_t size ) + : contents_( contents ) + , size_( ValidateSize(size) ) {} + + ReceivedPacket( const char *contents, std::size_t size ) + : contents_( contents ) + , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} + +#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)) + ReceivedPacket( const char *contents, int size ) + : contents_( contents ) + , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} +#endif + + bool IsMessage() const { return !IsBundle(); } + bool IsBundle() const; + + osc_bundle_element_size_t Size() const { return size_; } + const char *Contents() const { return contents_; } + +private: + const char *contents_; + osc_bundle_element_size_t size_; + + static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size ) + { + // sanity check integer types declared in OscTypes.h + // you'll need to fix OscTypes.h if any of these asserts fail + assert( sizeof(osc::int32) == 4 ); + assert( sizeof(osc::uint32) == 4 ); + assert( sizeof(osc::int64) == 8 ); + assert( sizeof(osc::uint64) == 8 ); + + if( !IsValidElementSizeValue(size) ) + throw MalformedPacketException( "invalid packet size" ); + + if( size == 0 ) + throw MalformedPacketException( "zero length elements not permitted" ); + + if( !IsMultipleOf4(size) ) + throw MalformedPacketException( "element size must be multiple of four" ); + + return size; + } +}; + + +class ReceivedBundleElement{ +public: + ReceivedBundleElement( const char *sizePtr ) + : sizePtr_( sizePtr ) {} + + friend class ReceivedBundleElementIterator; + + bool IsMessage() const { return !IsBundle(); } + bool IsBundle() const; + + osc_bundle_element_size_t Size() const; + const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; } + +private: + const char *sizePtr_; +}; + + +class ReceivedBundleElementIterator{ +public: + ReceivedBundleElementIterator( const char *sizePtr ) + : value_( sizePtr ) {} + + ReceivedBundleElementIterator operator++() + { + Advance(); + return *this; + } + + ReceivedBundleElementIterator operator++(int) + { + ReceivedBundleElementIterator old( *this ); + Advance(); + return old; + } + + const ReceivedBundleElement& operator*() const { return value_; } + + const ReceivedBundleElement* operator->() const { return &value_; } + + friend bool operator==(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ); + +private: + ReceivedBundleElement value_; + + void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); } + + bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const + { + return value_.sizePtr_ == rhs.value_.sizePtr_; + } +}; + +inline bool operator==(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ) +{ + return lhs.IsEqualTo( rhs ); +} + +inline bool operator!=(const ReceivedBundleElementIterator& lhs, + const ReceivedBundleElementIterator& rhs ) +{ + return !( lhs == rhs ); +} + + +class ReceivedMessageArgument{ +public: + ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr ) + : typeTagPtr_( typeTagPtr ) + , argumentPtr_( argumentPtr ) {} + + friend class ReceivedMessageArgumentIterator; + + char TypeTag() const { return *typeTagPtr_; } + + // the unchecked methods below don't check whether the argument actually + // is of the specified type. they should only be used if you've already + // checked the type tag or the associated IsType() method. + + bool IsBool() const + { return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; } + bool AsBool() const; + bool AsBoolUnchecked() const; + + bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; } + bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; } + + bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; } + int32 AsInt32() const; + int32 AsInt32Unchecked() const; + + bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; } + float AsFloat() const; + float AsFloatUnchecked() const; + + bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; } + char AsChar() const; + char AsCharUnchecked() const; + + bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; } + uint32 AsRgbaColor() const; + uint32 AsRgbaColorUnchecked() const; + + bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; } + uint32 AsMidiMessage() const; + uint32 AsMidiMessageUnchecked() const; + + bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; } + int64 AsInt64() const; + int64 AsInt64Unchecked() const; + + bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; } + uint64 AsTimeTag() const; + uint64 AsTimeTagUnchecked() const; + + bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; } + double AsDouble() const; + double AsDoubleUnchecked() const; + + bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; } + const char* AsString() const; + const char* AsStringUnchecked() const { return argumentPtr_; } + + bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; } + const char* AsSymbol() const; + const char* AsSymbolUnchecked() const { return argumentPtr_; } + + bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; } + void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const; + void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const; + + bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; } + bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; } + // Calculate the number of top-level items in the array. Nested arrays count as one item. + // Only valid at array start. Will throw an exception if IsArrayStart() == false. + std::size_t ComputeArrayItemCount() const; + +private: + const char *typeTagPtr_; + const char *argumentPtr_; +}; + + +class ReceivedMessageArgumentIterator{ +public: + ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) + : value_( typeTags, arguments ) {} + + ReceivedMessageArgumentIterator operator++() + { + Advance(); + return *this; + } + + ReceivedMessageArgumentIterator operator++(int) + { + ReceivedMessageArgumentIterator old( *this ); + Advance(); + return old; + } + + const ReceivedMessageArgument& operator*() const { return value_; } + + const ReceivedMessageArgument* operator->() const { return &value_; } + + friend bool operator==(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ); + +private: + ReceivedMessageArgument value_; + + void Advance(); + + bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const + { + return value_.typeTagPtr_ == rhs.value_.typeTagPtr_; + } +}; + +inline bool operator==(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ) +{ + return lhs.IsEqualTo( rhs ); +} + +inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, + const ReceivedMessageArgumentIterator& rhs ) +{ + return !( lhs == rhs ); +} + + +class ReceivedMessageArgumentStream{ + friend class ReceivedMessage; + ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, + const ReceivedMessageArgumentIterator& end ) + : p_( begin ) + , end_( end ) {} + + ReceivedMessageArgumentIterator p_, end_; + +public: + + // end of stream + bool Eos() const { return p_ == end_; } + + ReceivedMessageArgumentStream& operator>>( bool& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsBool(); + return *this; + } + + // not sure if it would be useful to stream Nil and Infinitum + // for now it's not possible + // same goes for array boundaries + + ReceivedMessageArgumentStream& operator>>( int32& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsInt32(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( float& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsFloat(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( char& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsChar(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsRgbaColor(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsMidiMessage(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( int64& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsInt64(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsTimeTag(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( double& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsDouble(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( Blob& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + (*p_++).AsBlob( rhs.data, rhs.size ); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( const char*& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs = (*p_++).AsString(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) + { + if( Eos() ) + throw MissingArgumentException(); + + rhs.value = (*p_++).AsSymbol(); + return *this; + } + + ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) + { + (void) rhs; // suppress unused parameter warning + + if( !Eos() ) + throw ExcessArgumentException(); + + return *this; + } +}; + + +class ReceivedMessage{ + void Init( const char *bundle, osc_bundle_element_size_t size ); +public: + explicit ReceivedMessage( const ReceivedPacket& packet ); + explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); + + const char *AddressPattern() const { return addressPattern_; } + + // Support for non-standard SuperCollider integer address patterns: + bool AddressPatternIsUInt32() const; + uint32 AddressPatternAsUInt32() const; + + uint32 ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } + + const char *TypeTags() const { return typeTagsBegin_; } + + + typedef ReceivedMessageArgumentIterator const_iterator; + + ReceivedMessageArgumentIterator ArgumentsBegin() const + { + return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); + } + + ReceivedMessageArgumentIterator ArgumentsEnd() const + { + return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); + } + + ReceivedMessageArgumentStream ArgumentStream() const + { + return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); + } + +private: + const char *addressPattern_; + const char *typeTagsBegin_; + const char *typeTagsEnd_; + const char *arguments_; +}; + + +class ReceivedBundle{ + void Init( const char *message, osc_bundle_element_size_t size ); +public: + explicit ReceivedBundle( const ReceivedPacket& packet ); + explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); + + uint64 TimeTag() const; + + uint32 ElementCount() const { return elementCount_; } + + typedef ReceivedBundleElementIterator const_iterator; + + ReceivedBundleElementIterator ElementsBegin() const + { + return ReceivedBundleElementIterator( timeTag_ + 8 ); + } + + ReceivedBundleElementIterator ElementsEnd() const + { + return ReceivedBundleElementIterator( end_ ); + } + +private: + const char *timeTag_; + const char *end_; + uint32 elementCount_; +}; + + +} // namespace osc + + +#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */ diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.cpp b/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.cpp new file mode 100644 index 0000000000..444a9fed48 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.cpp @@ -0,0 +1,52 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#include "OscTypes.h" + +namespace osc{ + +BundleInitiator BeginBundleImmediate(1); +BundleTerminator EndBundle; +MessageTerminator EndMessage; +NilType OscNil; +#ifndef _OBJC_OBJC_H_ +NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead +#endif +InfinitumType Infinitum; +ArrayInitiator BeginArray; +ArrayTerminator EndArray; + +} // namespace osc diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.h b/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.h new file mode 100644 index 0000000000..53db577ea9 --- /dev/null +++ b/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.h @@ -0,0 +1,240 @@ +/* + oscpack -- Open Sound Control (OSC) packet manipulation library + http://www.rossbencina.com/code/oscpack + + Copyright (c) 2004-2013 Ross Bencina + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* + The text above constitutes the entire oscpack license; however, + the oscpack developer(s) also make the following non-binding requests: + + Any person wishing to distribute modifications to the Software is + requested to send the modifications to the original developer so that + they can be incorporated into the canonical version. It is also + requested that these non-binding requests be included whenever the + above license is reproduced. +*/ +#ifndef INCLUDED_OSCPACK_OSCTYPES_H +#define INCLUDED_OSCPACK_OSCTYPES_H + + +namespace osc{ + +// basic types + +#if defined(__BORLANDC__) || defined(_MSC_VER) + +typedef __int64 int64; +typedef unsigned __int64 uint64; + +#elif defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) + +typedef long int64; +typedef unsigned long uint64; + +#else + +typedef long long int64; +typedef unsigned long long uint64; + +#endif + + + +#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) + +typedef signed int int32; +typedef unsigned int uint32; + +#else + +typedef signed long int32; +typedef unsigned long uint32; + +#endif + + +enum ValueTypeSizes{ + OSC_SIZEOF_INT32 = 4, + OSC_SIZEOF_UINT32 = 4, + OSC_SIZEOF_INT64 = 8, + OSC_SIZEOF_UINT64 = 8, +}; + + +// osc_bundle_element_size_t is used for the size of bundle elements and blobs +// the OSC spec specifies these as int32 (signed) but we ensure that they +// are always positive since negative field sizes make no sense. + +typedef int32 osc_bundle_element_size_t; + +enum { + OSC_INT32_MAX = 0x7FFFFFFF, + + // Element sizes are specified to be int32, and are always rounded up to nearest + // multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC. + OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC +}; + + +inline bool IsValidElementSizeValue( osc_bundle_element_size_t x ) +{ + // sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX + return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX; +} + + +inline bool IsMultipleOf4( osc_bundle_element_size_t x ) +{ + return (x & ((osc_bundle_element_size_t)0x03)) == 0; +} + + +enum TypeTagValues { + TRUE_TYPE_TAG = 'T', + FALSE_TYPE_TAG = 'F', + NIL_TYPE_TAG = 'N', + INFINITUM_TYPE_TAG = 'I', + INT32_TYPE_TAG = 'i', + FLOAT_TYPE_TAG = 'f', + CHAR_TYPE_TAG = 'c', + RGBA_COLOR_TYPE_TAG = 'r', + MIDI_MESSAGE_TYPE_TAG = 'm', + INT64_TYPE_TAG = 'h', + TIME_TAG_TYPE_TAG = 't', + DOUBLE_TYPE_TAG = 'd', + STRING_TYPE_TAG = 's', + SYMBOL_TYPE_TAG = 'S', + BLOB_TYPE_TAG = 'b', + ARRAY_BEGIN_TYPE_TAG = '[', + ARRAY_END_TYPE_TAG = ']' +}; + + + +// i/o manipulators used for streaming interfaces + +struct BundleInitiator{ + explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {} + uint64 timeTag; +}; + +extern BundleInitiator BeginBundleImmediate; + +inline BundleInitiator BeginBundle( uint64 timeTag=1 ) +{ + return BundleInitiator(timeTag); +} + + +struct BundleTerminator{ +}; + +extern BundleTerminator EndBundle; + +struct BeginMessage{ + explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {} + const char *addressPattern; +}; + +struct MessageTerminator{ +}; + +extern MessageTerminator EndMessage; + + +// osc specific types. they are defined as structs so they can be used +// as separately identifiable types with the streaming operators. + +struct NilType{ +}; + +extern NilType OscNil; + +#ifndef _OBJC_OBJC_H_ +extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead +#endif + +struct InfinitumType{ +}; + +extern InfinitumType Infinitum; + +struct RgbaColor{ + RgbaColor() {} + explicit RgbaColor( uint32 value_ ) : value( value_ ) {} + uint32 value; + + operator uint32() const { return value; } +}; + + +struct MidiMessage{ + MidiMessage() {} + explicit MidiMessage( uint32 value_ ) : value( value_ ) {} + uint32 value; + + operator uint32() const { return value; } +}; + + +struct TimeTag{ + TimeTag() {} + explicit TimeTag( uint64 value_ ) : value( value_ ) {} + uint64 value; + + operator uint64() const { return value; } +}; + + +struct Symbol{ + Symbol() {} + explicit Symbol( const char* value_ ) : value( value_ ) {} + const char* value; + + operator const char *() const { return value; } +}; + + +struct Blob{ + Blob() {} + explicit Blob( const void* data_, osc_bundle_element_size_t size_ ) + : data( data_ ), size( size_ ) {} + const void* data; + osc_bundle_element_size_t size; +}; + +struct ArrayInitiator{ +}; + +extern ArrayInitiator BeginArray; + +struct ArrayTerminator{ +}; + +extern ArrayTerminator EndArray; + +} // namespace osc + + +#endif /* INCLUDED_OSCPACK_OSCTYPES_H */ diff --git a/modules/touch/include.cmake b/modules/touch/include.cmake new file mode 100644 index 0000000000..6eb8a40c99 --- /dev/null +++ b/modules/touch/include.cmake @@ -0,0 +1 @@ +set (DEFAULT_MODULE ON) \ No newline at end of file diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h new file mode 100644 index 0000000000..9c0cae9c92 --- /dev/null +++ b/modules/touch/include/TuioEar.h @@ -0,0 +1,62 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__ +#define __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__ + +#include +#include +#include +#include +#include +#include + + +using namespace TUIO2; + +class TuioEar : public TuioListener { + + public: + TuioEar(); + ~TuioEar() { + tuioClient->disconnect(); + delete tuioClient; + delete oscReceiver; + } + + void tuioAdd(TuioObject *tobj); + void tuioUpdate(TuioObject *tobj); + void tuioRemove(TuioObject *tobj); + void tuioRefresh(TuioTime frameTime); + + std::vector* getInput() { return &list; } + + private: + TuioClient *tuioClient; + OscReceiver *oscReceiver; + std::vector list; + std::vector::iterator it; +}; + +#endif // __OPENSPACE_MODULE_TOUCH___TOUCHWRAPPER___H__ diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp new file mode 100644 index 0000000000..74b5f29749 --- /dev/null +++ b/modules/touch/src/TuioEar.cpp @@ -0,0 +1,89 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include +#include // std::find + + +#include + +namespace { + const std::string _loggerCat = "TuioEar"; +} + +void TuioEar::tuioAdd(TuioObject *tobj) { + + if (tobj->containsNewTuioToken()) LINFO("add tok " << tobj->getTuioToken()->getSessionID() << "\n"); + if (tobj->containsNewTuioPointer()) { + list.push_back(tobj->getTuioPointer()); + LINFO("add ptr " << tobj->getTuioPointer()->getSessionID() << ", Fingers: " << list.size() << "\n"); + + } + if(tobj->containsNewTuioBounds()) LINFO("add bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); + if(tobj->containsNewTuioSymbol()) LINFO("add sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); + //std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; + //std::cout << std::flush; +} + +void TuioEar::tuioUpdate(TuioObject *tobj) { + if (tobj->containsTuioToken()) LINFO("set tok " << tobj->getTuioToken()->getSessionID() << "\n"); + if (tobj->containsTuioPointer()) LINFO("set ptr " << tobj->getTuioPointer()->getSessionID() << "\n"); + if (tobj->containsTuioBounds()) LINFO("set bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); + if (tobj->containsTuioSymbol()) LINFO("set sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); + //std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << " " << tobj->getMotionSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; + //std::cout << std::flush; +} + +void TuioEar::tuioRemove(TuioObject *tobj) { + if (tobj->containsTuioToken()) LINFO("del tok " << tobj->getTuioToken()->getSessionID() << "\n"); + + if (tobj->containsTuioPointer()) { + it = list.begin(); + for (; it != list.end(); ++it) { + if (it->getSessionID() == tobj->getTuioPointer()->getSessionID()) { + list.erase(it); + LINFO("del ptr " << tobj->getTuioPointer()->getSessionID() << ", Fingers: " << list.size() << "\n"); + break; + } + } + } + + if (tobj->containsTuioBounds()) LINFO("del bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); + if (tobj->containsTuioSymbol()) LINFO("del sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); + //std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ")" << std::endl; + //std::cout << std::flush; +} + +void TuioEar::tuioRefresh(TuioTime frameTime) { + LINFO("refresh " << frameTime.getFrameID() << " "<< frameTime.getTotalMilliseconds() << "\n"); +} + +TuioEar::TuioEar() { + oscReceiver = new UdpReceiver(3333); + //oscReceiver = new TcpReceiver("127.0.0.1",3333); + tuioClient = new TuioClient(oscReceiver); + tuioClient->addTuioListener(this); + tuioClient->connect(); +} diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp new file mode 100644 index 0000000000..e7041fcb64 --- /dev/null +++ b/modules/touch/touchmodule.cpp @@ -0,0 +1,33 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { + +TouchModule::TouchModule() + : OpenSpaceModule("Touch") +{} + +} // namespace openspace diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h new file mode 100644 index 0000000000..8c2549e58d --- /dev/null +++ b/modules/touch/touchmodule.h @@ -0,0 +1,39 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__ +#define __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__ + +#include + +namespace openspace { + +class TouchModule : public OpenSpaceModule { +public: + TouchModule(); +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__ diff --git a/openspace.cfg b/openspace.cfg index 5233af0293..c19cbbb29c 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,7 +7,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/default.scene", + Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", From 92b480f708d5d04b6d7e4e13e352957058bac137 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 17 Feb 2017 15:44:03 -0700 Subject: [PATCH 002/192] registerModuleCallback from touchmodule to call interaction handler --- apps/OpenSpace/main.cpp | 3 -- modules/touch/include/TuioEar.h | 20 ++++---- modules/touch/src/TuioEar.cpp | 61 +++++++++++++----------- modules/touch/touchmodule.cpp | 82 ++++++++++++++++++++++++++++++++- modules/touch/touchmodule.h | 3 ++ 5 files changed, 130 insertions(+), 39 deletions(-) diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 60d9c9fd87..bf0a8b7147 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -33,7 +33,6 @@ #include #include -#include sgct::Engine* _sgctEngine; @@ -110,8 +109,6 @@ int main(int argc, char** argv) { int main_main(int argc, char** argv) { auto glVersion = supportedOpenGLVersion(); - - TuioEar *ear = new TuioEar(); // create the OpenSpace engine and get arguments for the sgct engine std::vector sgctArguments; diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index 9c0cae9c92..fad7f5e821 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -31,7 +31,7 @@ #include #include #include - +#include using namespace TUIO2; @@ -40,9 +40,9 @@ class TuioEar : public TuioListener { public: TuioEar(); ~TuioEar() { - tuioClient->disconnect(); - delete tuioClient; - delete oscReceiver; + _tuioClient->disconnect(); + delete _tuioClient; + delete _oscReceiver; } void tuioAdd(TuioObject *tobj); @@ -50,13 +50,15 @@ class TuioEar : public TuioListener { void tuioRemove(TuioObject *tobj); void tuioRefresh(TuioTime frameTime); - std::vector* getInput() { return &list; } + std::vector getInput(); + void clearInput(); private: - TuioClient *tuioClient; - OscReceiver *oscReceiver; - std::vector list; - std::vector::iterator it; + TuioClient *_tuioClient; + OscReceiver *_oscReceiver; + + std::vector _list; + boost::mutex _mx; }; #endif // __OPENSPACE_MODULE_TOUCH___TOUCHWRAPPER___H__ diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 74b5f29749..13c2b5b612 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -24,66 +24,75 @@ #include #include -#include // std::find +#include +#include +#include +#include +#include +#include #include +#include namespace { const std::string _loggerCat = "TuioEar"; } void TuioEar::tuioAdd(TuioObject *tobj) { - - if (tobj->containsNewTuioToken()) LINFO("add tok " << tobj->getTuioToken()->getSessionID() << "\n"); if (tobj->containsNewTuioPointer()) { - list.push_back(tobj->getTuioPointer()); - LINFO("add ptr " << tobj->getTuioPointer()->getSessionID() << ", Fingers: " << list.size() << "\n"); + boost::lock_guard lock(_mx); + _list.push_back(tobj); + LINFO("add ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); } + if (tobj->containsNewTuioToken()) LINFO("add tok " << tobj->getTuioToken()->getSessionID() << "\n"); if(tobj->containsNewTuioBounds()) LINFO("add bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); if(tobj->containsNewTuioSymbol()) LINFO("add sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); //std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; - //std::cout << std::flush; } void TuioEar::tuioUpdate(TuioObject *tobj) { + if (tobj->containsTuioPointer()) { + boost::lock_guard lock(_mx); + _list.push_back(tobj); + + LINFO("set ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); + } if (tobj->containsTuioToken()) LINFO("set tok " << tobj->getTuioToken()->getSessionID() << "\n"); - if (tobj->containsTuioPointer()) LINFO("set ptr " << tobj->getTuioPointer()->getSessionID() << "\n"); if (tobj->containsTuioBounds()) LINFO("set bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); if (tobj->containsTuioSymbol()) LINFO("set sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); //std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << " " << tobj->getMotionSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; - //std::cout << std::flush; } void TuioEar::tuioRemove(TuioObject *tobj) { - if (tobj->containsTuioToken()) LINFO("del tok " << tobj->getTuioToken()->getSessionID() << "\n"); - if (tobj->containsTuioPointer()) { - it = list.begin(); - for (; it != list.end(); ++it) { - if (it->getSessionID() == tobj->getTuioPointer()->getSessionID()) { - list.erase(it); - LINFO("del ptr " << tobj->getTuioPointer()->getSessionID() << ", Fingers: " << list.size() << "\n"); - break; - } - } + LINFO("del ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); } - + if (tobj->containsTuioToken()) LINFO("del tok " << tobj->getTuioToken()->getSessionID() << "\n"); if (tobj->containsTuioBounds()) LINFO("del bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); if (tobj->containsTuioSymbol()) LINFO("del sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); //std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ")" << std::endl; - //std::cout << std::flush; } void TuioEar::tuioRefresh(TuioTime frameTime) { LINFO("refresh " << frameTime.getFrameID() << " "<< frameTime.getTotalMilliseconds() << "\n"); } -TuioEar::TuioEar() { - oscReceiver = new UdpReceiver(3333); - //oscReceiver = new TcpReceiver("127.0.0.1",3333); - tuioClient = new TuioClient(oscReceiver); - tuioClient->addTuioListener(this); - tuioClient->connect(); +std::vector TuioEar::getInput() { + boost::lock_guard lock(_mx); + return _list; +} + +void TuioEar::clearInput() { + boost::lock_guard lock(_mx); + _list.clear(); +} + +TuioEar::TuioEar() { + _oscReceiver = new UdpReceiver(3333); + //oscReceiver = new TcpReceiver("127.0.0.1",3333); + _tuioClient = new TuioClient(_oscReceiver); + _tuioClient->addTuioListener(this); + _tuioClient->connect(); } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index e7041fcb64..dcf5249231 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -23,11 +23,91 @@ ****************************************************************************************/ #include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include namespace openspace { + TuioEar TouchModule::*ear; + TouchModule::TouchModule() : OpenSpaceModule("Touch") -{} +{ + + OsEng.registerModuleCallback( + OpenSpaceEngine::CallbackOption::Initialize, + []() { + LDEBUGC("TouchModule", "Initializing TuioEar"); + ear = new TuioEar(); + } + ); + + OsEng.registerModuleCallback( + OpenSpaceEngine::CallbackOption::Deinitialize, + []() { + LDEBUGC("TouchModule", "Deinitialize TuioEar"); + delete ear; + } + ); + + OsEng.registerModuleCallback( + OpenSpaceEngine::CallbackOption::PostSyncPreDraw, + []() { + WindowWrapper& wrapper = OsEng.windowWrapper(); + if (OsEng.isMaster() && wrapper.isRegularRendering()) { + std::vector list = ear->getInput(); + std::vector::iterator it = list.begin(); + + // step through the list (from the start) and find each unique id tuioobject + std::vector group; + + for (auto &&i : list) { + bool sameId = false; + glm::vec2 centroid = glm::vec2(0.0f, 0.0f); + if (i->containsTuioPointer()) { + int id = i->getSessionID(); + for (auto &&j : group) // change to lambda/find function + if (j->getSessionID() == id) + sameId = true; // step out of for + if (sameId) { // calculate a centroid + for (auto &&j : group) { + centroid.x += j->getTuioPointer()->getX(); + centroid.y += j->getTuioPointer()->getY(); + } + centroid.x /= group.size(); + centroid.y /= group.size(); + } + else + group.push_back(i); + + + } + } + + // group + } + } + ); + + OsEng.registerModuleCallback( + OpenSpaceEngine::CallbackOption::PostDraw, + []() { + WindowWrapper& wrapper = OsEng.windowWrapper(); + if (OsEng.isMaster() && wrapper.isRegularRendering()) { + ear->clearInput(); + } + } + ); +} } // namespace openspace diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 8c2549e58d..772da90639 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -26,12 +26,15 @@ #define __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__ #include +#include namespace openspace { class TouchModule : public OpenSpaceModule { public: TouchModule(); + + static TuioEar *ear; }; } // namespace openspace From 2d223dc25043990ea0ad8bfd055e9bb4ab7b820f Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Sat, 18 Feb 2017 22:11:48 -0700 Subject: [PATCH 003/192] using std::mutex over boost, debug prints for touch input in touchmodule --- modules/touch/ext/libTUIO2/TUIO2/TuioObject.h | 6 ++ modules/touch/include/TuioEar.h | 5 +- modules/touch/src/TuioEar.cpp | 19 ++-- modules/touch/touchmodule.cpp | 92 +++++++++++-------- modules/touch/touchmodule.h | 2 +- 5 files changed, 74 insertions(+), 50 deletions(-) diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h index 4e18103b86..e3f141a9a7 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h +++ b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h @@ -82,6 +82,12 @@ namespace TUIO2 { */ TuioObject (unsigned int s_id); + /** + * Copy constructor takes a reference of a TuioObject + * @param t the reference TuioObject to assign + */ + //TuioObject(const TuioObject &t); + /** * This constructor takes a TuioTime and the Session ID * @param ttime the TuioTime to assign diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index fad7f5e821..e356b5d5ab 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -31,7 +31,7 @@ #include #include #include -#include +#include using namespace TUIO2; @@ -52,13 +52,14 @@ class TuioEar : public TuioListener { std::vector getInput(); void clearInput(); + void unlock() { _mx.unlock(); }; private: TuioClient *_tuioClient; OscReceiver *_oscReceiver; std::vector _list; - boost::mutex _mx; + std::mutex _mx; }; #endif // __OPENSPACE_MODULE_TOUCH___TOUCHWRAPPER___H__ diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 13c2b5b612..fef96aacb7 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -33,7 +33,7 @@ #include #include -#include +#include namespace { const std::string _loggerCat = "TuioEar"; @@ -41,28 +41,30 @@ namespace { void TuioEar::tuioAdd(TuioObject *tobj) { if (tobj->containsNewTuioPointer()) { - boost::lock_guard lock(_mx); + _mx.lock(); _list.push_back(tobj); - LINFO("add ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); + //LINFO("add ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); } if (tobj->containsNewTuioToken()) LINFO("add tok " << tobj->getTuioToken()->getSessionID() << "\n"); if(tobj->containsNewTuioBounds()) LINFO("add bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); if(tobj->containsNewTuioSymbol()) LINFO("add sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); //std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; + _mx.unlock(); } void TuioEar::tuioUpdate(TuioObject *tobj) { if (tobj->containsTuioPointer()) { - boost::lock_guard lock(_mx); + _mx.lock(); _list.push_back(tobj); - LINFO("set ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); + //LINFO("set ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); } if (tobj->containsTuioToken()) LINFO("set tok " << tobj->getTuioToken()->getSessionID() << "\n"); if (tobj->containsTuioBounds()) LINFO("set bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); if (tobj->containsTuioSymbol()) LINFO("set sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); //std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << " " << tobj->getMotionSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; + _mx.unlock(); } void TuioEar::tuioRemove(TuioObject *tobj) { @@ -76,17 +78,18 @@ void TuioEar::tuioRemove(TuioObject *tobj) { } void TuioEar::tuioRefresh(TuioTime frameTime) { - LINFO("refresh " << frameTime.getFrameID() << " "<< frameTime.getTotalMilliseconds() << "\n"); + //LINFO("refresh " << frameTime.getFrameID() << " "<< frameTime.getTotalMilliseconds() << "\n"); } std::vector TuioEar::getInput() { - boost::lock_guard lock(_mx); + _mx.lock(); return _list; } void TuioEar::clearInput() { - boost::lock_guard lock(_mx); + _mx.lock(); _list.clear(); + _mx.unlock(); } TuioEar::TuioEar() { diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index dcf5249231..e585919812 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -36,6 +36,10 @@ #include #include +#include +#include +#include + namespace openspace { TuioEar TouchModule::*ear; @@ -46,68 +50,78 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::Initialize, - []() { + [&]() { LDEBUGC("TouchModule", "Initializing TuioEar"); ear = new TuioEar(); } ); - + OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::Deinitialize, - []() { + [&]() { LDEBUGC("TouchModule", "Deinitialize TuioEar"); delete ear; } ); - OsEng.registerModuleCallback( - OpenSpaceEngine::CallbackOption::PostSyncPreDraw, - []() { - WindowWrapper& wrapper = OsEng.windowWrapper(); - if (OsEng.isMaster() && wrapper.isRegularRendering()) { - std::vector list = ear->getInput(); - std::vector::iterator it = list.begin(); - - // step through the list (from the start) and find each unique id tuioobject - std::vector group; - - for (auto &&i : list) { - bool sameId = false; - glm::vec2 centroid = glm::vec2(0.0f, 0.0f); - if (i->containsTuioPointer()) { - int id = i->getSessionID(); - for (auto &&j : group) // change to lambda/find function - if (j->getSessionID() == id) - sameId = true; // step out of for - if (sameId) { // calculate a centroid - for (auto &&j : group) { - centroid.x += j->getTuioPointer()->getX(); - centroid.y += j->getTuioPointer()->getY(); - } - centroid.x /= group.size(); - centroid.y /= group.size(); - } - else - group.push_back(i); - - - } - } - - // group + OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw + OpenSpaceEngine::CallbackOption::PreSync, + [&]() { + std::vector list = ear->getInput(); + std::vector group; + glm::vec2 centroid; + ear->unlock(); + std::string s = ""; + //print list for debugging + const std::string _loggerCat = "TouchModule"; + std::ostringstream os; + for (auto &&j : list) { + os << " (" << j->getTuioPointer()->getX() << "," << j->getTuioPointer()->getY() << ") "; } + if (list.size() > 0) + LINFO("List size: " << list.size() << os.str() << "\n"); + os.clear(); + + // step through the list (from the start) and find each unique id TuioObject + for (auto &&i : list) { + bool sameId = false; + centroid = glm::vec2(0.0f, 0.0f); + if (i->containsTuioPointer()) { // sanity check + int id = i->getSessionID(); + for (auto &&j : group) // change to lambda/find function + if (j->getSessionID() == id) + sameId = true; // step out of for + if (sameId) { // calculate a centroid + for (auto &&j : group) { + centroid.x += j->getTuioPointer()->getX(); + centroid.y += j->getTuioPointer()->getY(); + } + centroid.x /= group.size(); + centroid.y /= group.size(); + } + else + group.push_back(i); + + + } + } + + //if (centroid.x + centroid.y != 0.0f) + //LINFO("List size: " << list.size() << ", Centroid: (" << centroid.x << ", " << centroid.y << ")\n"); + // group } ); OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::PostDraw, - []() { + [&]() { WindowWrapper& wrapper = OsEng.windowWrapper(); if (OsEng.isMaster() && wrapper.isRegularRendering()) { ear->clearInput(); } } ); + } } // namespace openspace diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 772da90639..7f14817d58 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -34,7 +34,7 @@ class TouchModule : public OpenSpaceModule { public: TouchModule(); - static TuioEar *ear; + TuioEar *ear; }; } // namespace openspace From c4bd08c19ed0d3e27fc9488de9dbf5195f33d904 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 21 Feb 2017 14:00:36 -0700 Subject: [PATCH 004/192] change TUIO protocol from v2.0 to v1.1 to support a wider range of sender applications --- .gitignore | 2 + modules/touch/CMakeLists.txt | 2 +- .../ext/{libTUIO2 => libTUIO}/CMakeLists.txt | 50 +- .../{libTUIO2/TUIO2 => libTUIO/TUIO}/Doxyfile | 2 +- .../TUIO2 => libTUIO/TUIO}/FlashSender.cpp | 6 +- .../TUIO2 => libTUIO/TUIO}/FlashSender.h | 6 +- .../TUIO2 => libTUIO/TUIO}/LibExport.h | 0 .../touch/ext/libTUIO/TUIO/OneEuroFilter.cpp | 66 ++ .../touch/ext/libTUIO/TUIO/OneEuroFilter.h | 90 ++ .../TUIO2 => libTUIO/TUIO}/OscReceiver.cpp | 10 +- .../TUIO2 => libTUIO/TUIO}/OscReceiver.h | 8 +- .../TUIO2 => libTUIO/TUIO}/OscSender.h | 8 +- .../TUIO2 => libTUIO/TUIO}/TcpReceiver.cpp | 27 +- .../TUIO2 => libTUIO/TUIO}/TcpReceiver.h | 12 +- .../TUIO2 => libTUIO/TUIO}/TcpSender.cpp | 2 +- .../TUIO2 => libTUIO/TUIO}/TcpSender.h | 4 +- modules/touch/ext/libTUIO/TUIO/TuioBlob.cpp | 253 ++++++ .../TuioBounds.h => libTUIO/TUIO/TuioBlob.h} | 189 ++-- modules/touch/ext/libTUIO/TUIO/TuioClient.cpp | 849 ++++++++++++++++++ modules/touch/ext/libTUIO/TUIO/TuioClient.h | 301 +++++++ .../touch/ext/libTUIO/TUIO/TuioContainer.cpp | 277 ++++++ .../touch/ext/libTUIO/TUIO/TuioContainer.h | 279 ++++++ modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp | 38 + modules/touch/ext/libTUIO/TUIO/TuioCursor.h | 86 ++ .../touch/ext/libTUIO/TUIO/TuioDispatcher.cpp | 211 +++++ .../touch/ext/libTUIO/TUIO/TuioDispatcher.h | 187 ++++ modules/touch/ext/libTUIO/TUIO/TuioListener.h | 124 +++ .../touch/ext/libTUIO/TUIO/TuioManager.cpp | 615 +++++++++++++ modules/touch/ext/libTUIO/TUIO/TuioManager.h | 389 ++++++++ modules/touch/ext/libTUIO/TUIO/TuioObject.cpp | 165 ++++ modules/touch/ext/libTUIO/TUIO/TuioObject.h | 213 +++++ .../TUIO2 => libTUIO/TUIO}/TuioPoint.cpp | 78 +- .../TUIO2 => libTUIO/TUIO}/TuioPoint.h | 81 +- modules/touch/ext/libTUIO/TUIO/TuioServer.cpp | 634 +++++++++++++ .../TUIO2 => libTUIO/TUIO}/TuioServer.h | 146 +-- .../TUIO2 => libTUIO/TUIO}/TuioTime.cpp | 53 +- .../TUIO2 => libTUIO/TUIO}/TuioTime.h | 47 +- .../TUIO2 => libTUIO/TUIO}/UdpReceiver.cpp | 8 +- .../TUIO2 => libTUIO/TUIO}/UdpReceiver.h | 10 +- .../TUIO2 => libTUIO/TUIO}/UdpSender.cpp | 2 +- .../TUIO2 => libTUIO/TUIO}/UdpSender.h | 6 +- .../TUIO2 => libTUIO/TUIO}/WebSockSender.cpp | 3 +- .../TUIO2 => libTUIO/TUIO}/WebSockSender.h | 2 +- .../ext/{libTUIO2 => libTUIO}/oscpack/CHANGES | 0 .../ext/{libTUIO2 => libTUIO}/oscpack/LICENSE | 0 .../ext/{libTUIO2 => libTUIO}/oscpack/README | 0 .../ext/{libTUIO2 => libTUIO}/oscpack/TODO | 0 .../oscpack/ip/IpEndpointName.cpp | 0 .../oscpack/ip/IpEndpointName.h | 0 .../oscpack/ip/NetworkingUtils.h | 0 .../oscpack/ip/PacketListener.h | 0 .../oscpack/ip/TimerListener.h | 0 .../oscpack/ip/UdpSocket.h | 0 .../oscpack/ip/posix/NetworkingUtils.cpp | 2 +- .../oscpack/ip/posix/UdpSocket.cpp | 6 +- .../oscpack/ip/win32/NetworkingUtils.cpp | 0 .../oscpack/ip/win32/UdpSocket.cpp | 0 .../osc/MessageMappingOscPacketListener.h | 0 .../oscpack/osc/OscException.h | 0 .../oscpack/osc/OscHostEndianness.h | 0 .../oscpack/osc/OscOutboundPacketStream.cpp | 0 .../oscpack/osc/OscOutboundPacketStream.h | 0 .../oscpack/osc/OscPacketListener.h | 0 .../oscpack/osc/OscPrintReceivedElements.cpp | 0 .../oscpack/osc/OscPrintReceivedElements.h | 0 .../oscpack/osc/OscReceivedElements.cpp | 0 .../oscpack/osc/OscReceivedElements.h | 0 .../oscpack/osc/OscTypes.cpp | 0 .../oscpack/osc/OscTypes.h | 0 .../touch/ext/libTUIO2/TUIO2/TuioBounds.cpp | 94 -- .../touch/ext/libTUIO2/TUIO2/TuioClient.cpp | 520 ----------- modules/touch/ext/libTUIO2/TUIO2/TuioClient.h | 241 ----- .../ext/libTUIO2/TUIO2/TuioComponent.cpp | 245 ----- .../touch/ext/libTUIO2/TUIO2/TuioComponent.h | 287 ------ .../ext/libTUIO2/TUIO2/TuioDispatcher.cpp | 165 ---- .../touch/ext/libTUIO2/TUIO2/TuioDispatcher.h | 169 ---- .../touch/ext/libTUIO2/TUIO2/TuioListener.h | 80 -- .../touch/ext/libTUIO2/TUIO2/TuioManager.cpp | 575 ------------ .../touch/ext/libTUIO2/TUIO2/TuioManager.h | 601 ------------- .../touch/ext/libTUIO2/TUIO2/TuioObject.cpp | 311 ------- modules/touch/ext/libTUIO2/TUIO2/TuioObject.h | 347 ------- .../touch/ext/libTUIO2/TUIO2/TuioPointer.cpp | 132 --- .../touch/ext/libTUIO2/TUIO2/TuioPointer.h | 263 ------ .../touch/ext/libTUIO2/TUIO2/TuioServer.cpp | 329 ------- modules/touch/ext/libTUIO2/TUIO2/TuioSource.h | 244 ----- .../touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp | 91 -- modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h | 160 ---- .../touch/ext/libTUIO2/TUIO2/TuioToken.cpp | 69 -- modules/touch/ext/libTUIO2/TUIO2/TuioToken.h | 151 ---- modules/touch/include/TuioEar.h | 32 +- modules/touch/src/TuioEar.cpp | 79 +- modules/touch/touchmodule.cpp | 16 +- 92 files changed, 5296 insertions(+), 5454 deletions(-) rename modules/touch/ext/{libTUIO2 => libTUIO}/CMakeLists.txt (69%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/Doxyfile (90%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/FlashSender.cpp (99%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/FlashSender.h (99%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/LibExport.h (100%) create mode 100644 modules/touch/ext/libTUIO/TUIO/OneEuroFilter.cpp create mode 100644 modules/touch/ext/libTUIO/TUIO/OneEuroFilter.h rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/OscReceiver.cpp (89%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/OscReceiver.h (95%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/OscSender.h (97%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TcpReceiver.cpp (92%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TcpReceiver.h (91%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TcpSender.cpp (99%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TcpSender.h (99%) create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioBlob.cpp rename modules/touch/ext/{libTUIO2/TUIO2/TuioBounds.h => libTUIO/TUIO/TuioBlob.h} (51%) create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioClient.cpp create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioClient.h create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioContainer.cpp create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioContainer.h create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioCursor.h create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioDispatcher.cpp create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioDispatcher.h create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioListener.h create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioManager.cpp create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioManager.h create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioObject.cpp create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioObject.h rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TuioPoint.cpp (62%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TuioPoint.h (85%) create mode 100644 modules/touch/ext/libTUIO/TUIO/TuioServer.cpp rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TuioServer.h (53%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TuioTime.cpp (69%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/TuioTime.h (81%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/UdpReceiver.cpp (91%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/UdpReceiver.h (91%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/UdpSender.cpp (99%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/UdpSender.h (98%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/WebSockSender.cpp (99%) rename modules/touch/ext/{libTUIO2/TUIO2 => libTUIO/TUIO}/WebSockSender.h (99%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/CHANGES (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/LICENSE (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/README (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/TODO (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/IpEndpointName.cpp (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/IpEndpointName.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/NetworkingUtils.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/PacketListener.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/TimerListener.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/UdpSocket.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/posix/NetworkingUtils.cpp (98%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/posix/UdpSocket.cpp (99%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/win32/NetworkingUtils.cpp (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/ip/win32/UdpSocket.cpp (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/MessageMappingOscPacketListener.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscException.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscHostEndianness.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscOutboundPacketStream.cpp (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscOutboundPacketStream.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscPacketListener.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscPrintReceivedElements.cpp (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscPrintReceivedElements.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscReceivedElements.cpp (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscReceivedElements.h (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscTypes.cpp (100%) rename modules/touch/ext/{libTUIO2 => libTUIO}/oscpack/osc/OscTypes.h (100%) delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioClient.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioListener.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioManager.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioObject.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioSource.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp delete mode 100644 modules/touch/ext/libTUIO2/TUIO2/TuioToken.h diff --git a/.gitignore b/.gitignore index b6c4278bba..38d00d5e83 100644 --- a/.gitignore +++ b/.gitignore @@ -119,3 +119,5 @@ data/spice/OsirisRexKernels data/spice/plu055.bsp data/spice/Rosetta data/spice/sat375.bsp +data/scene/lodglobes/saturn/Launcher.config +data/scene/lodglobes/mars/test_stats \ No newline at end of file diff --git a/modules/touch/CMakeLists.txt b/modules/touch/CMakeLists.txt index c2e655c546..96a5b695bb 100644 --- a/modules/touch/CMakeLists.txt +++ b/modules/touch/CMakeLists.txt @@ -40,4 +40,4 @@ create_new_module( ${HEADER_FILES} ${SOURCE_FILES} ) -include_external_library(${touch_module} libTUIO2 ${CMAKE_CURRENT_SOURCE_DIR}/ext/libTUIO2) \ No newline at end of file +include_external_library(${touch_module} libTUIO ${CMAKE_CURRENT_SOURCE_DIR}/ext/libTUIO) \ No newline at end of file diff --git a/modules/touch/ext/libTUIO2/CMakeLists.txt b/modules/touch/ext/libTUIO/CMakeLists.txt similarity index 69% rename from modules/touch/ext/libTUIO2/CMakeLists.txt rename to modules/touch/ext/libTUIO/CMakeLists.txt index 4fe0af8650..a1f97f67fa 100644 --- a/modules/touch/ext/libTUIO2/CMakeLists.txt +++ b/modules/touch/ext/libTUIO/CMakeLists.txt @@ -22,29 +22,33 @@ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ######################################################################################### -project(libTUIO2) -message(STATUS "Generating libTUIO2 project") +project(libTUIO) +message(STATUS "Generating libTUIO project") -add_library(libTUIO2 - ${PROJECT_SOURCE_DIR}/TUIO2/WebSockSender.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/UdpSender.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/UdpReceiver.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioToken.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioTime.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioSymbol.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioServer.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioPointer.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioPoint.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioObject.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioManager.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioDispatcher.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioComponent.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioClient.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TuioBounds.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TcpSender.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/TcpReceiver.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/OscReceiver.cpp - ${PROJECT_SOURCE_DIR}/TUIO2/FlashSender.cpp +add_library(libTUIO + ${PROJECT_SOURCE_DIR}/TUIO/WebSockSender.cpp + ${PROJECT_SOURCE_DIR}/TUIO/UdpSender.cpp + ${PROJECT_SOURCE_DIR}/TUIO/UdpReceiver.cpp + #${PROJECT_SOURCE_DIR}/TUIO2/TuioToken.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioTime.cpp + #${PROJECT_SOURCE_DIR}/TUIO2/TuioSymbol.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioServer.cpp + #${PROJECT_SOURCE_DIR}/TUIO2/TuioPointer.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioPoint.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioObject.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioManager.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioDispatcher.cpp + #${PROJECT_SOURCE_DIR}/TUIO2/TuioComponent.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioCursor.cpp # + ${PROJECT_SOURCE_DIR}/TUIO/TuioContainer.cpp # + ${PROJECT_SOURCE_DIR}/TUIO/TuioClient.cpp + #${PROJECT_SOURCE_DIR}/TUIO2/TuioBounds.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioBlob.cpp # + ${PROJECT_SOURCE_DIR}/TUIO/TcpSender.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TcpReceiver.cpp + ${PROJECT_SOURCE_DIR}/TUIO/OscReceiver.cpp + ${PROJECT_SOURCE_DIR}/TUIO/OneEuroFilter.cpp # + ${PROJECT_SOURCE_DIR}/TUIO/FlashSender.cpp ${PROJECT_SOURCE_DIR}/oscpack/ip/IpEndpointName.cpp @@ -60,4 +64,4 @@ add_library(libTUIO2 ${PROJECT_SOURCE_DIR}/oscpack/osc/OscPrintReceivedElements.cpp ${PROJECT_SOURCE_DIR}/oscpack/osc/OscOutboundPacketStream.cpp ) -target_include_directories(libTUIO2 PUBLIC ${PROJECT_SOURCE_DIR}) \ No newline at end of file +target_include_directories(libTUIO PUBLIC ${PROJECT_SOURCE_DIR}) \ No newline at end of file diff --git a/modules/touch/ext/libTUIO2/TUIO2/Doxyfile b/modules/touch/ext/libTUIO/TUIO/Doxyfile similarity index 90% rename from modules/touch/ext/libTUIO2/TUIO2/Doxyfile rename to modules/touch/ext/libTUIO/TUIO/Doxyfile index 123a23ec35..5c43ffc2dd 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/Doxyfile +++ b/modules/touch/ext/libTUIO/TUIO/Doxyfile @@ -1,7 +1,7 @@ # Doxyfile 1.5.6 # Project related configuration options DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "TUIO2 C++ Developer API" +PROJECT_NAME = "TUIO C++ Developer API" # Build related configuration options EXTRACT_ALL = NO EXTRACT_PRIVATE = NO diff --git a/modules/touch/ext/libTUIO2/TUIO2/FlashSender.cpp b/modules/touch/ext/libTUIO/TUIO/FlashSender.cpp similarity index 99% rename from modules/touch/ext/libTUIO2/TUIO2/FlashSender.cpp rename to modules/touch/ext/libTUIO/TUIO/FlashSender.cpp index d3e9f2237b..29fb623807 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/FlashSender.cpp +++ b/modules/touch/ext/libTUIO/TUIO/FlashSender.cpp @@ -614,7 +614,7 @@ errorReturn: License along with this library. */ -using namespace TUIO2; +using namespace TUIO; FlashSender::FlashSender() { local = true; @@ -640,8 +640,8 @@ bool FlashSender::isConnected() { } bool FlashSender::sendOscPacket (osc::OutboundPacketStream *bundle) { - if (lcConnection==NULL)return false; - if (!TFLCSConnectionHasConnectedClient(lcConnection))return false; + if (lcConnection==NULL) return false; + if (!TFLCSConnectionHasConnectedClient(lcConnection)) return false; if ( bundle->Size() > buffer_size ) return false; if ( bundle->Size() == 0 ) return false; diff --git a/modules/touch/ext/libTUIO2/TUIO2/FlashSender.h b/modules/touch/ext/libTUIO/TUIO/FlashSender.h similarity index 99% rename from modules/touch/ext/libTUIO2/TUIO2/FlashSender.h rename to modules/touch/ext/libTUIO/TUIO/FlashSender.h index c584f8908e..7dd4684a7a 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/FlashSender.h +++ b/modules/touch/ext/libTUIO/TUIO/FlashSender.h @@ -163,14 +163,14 @@ typedef DWORD u_int32_t; #define DEFAULT_LC_CONN_NAME "_OscDataStream" #define DEFAULT_LC_METH_NAME "receiveOscData" -namespace TUIO2 { +namespace TUIO { /** * The FlashSender implements the Flash LocalConnection transport method for OSC * * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ + * @version 1.1.6 + */ class LIBDECL FlashSender : public OscSender { public: diff --git a/modules/touch/ext/libTUIO2/TUIO2/LibExport.h b/modules/touch/ext/libTUIO/TUIO/LibExport.h similarity index 100% rename from modules/touch/ext/libTUIO2/TUIO2/LibExport.h rename to modules/touch/ext/libTUIO/TUIO/LibExport.h diff --git a/modules/touch/ext/libTUIO/TUIO/OneEuroFilter.cpp b/modules/touch/ext/libTUIO/TUIO/OneEuroFilter.cpp new file mode 100644 index 0000000000..dceaa94f63 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/OneEuroFilter.cpp @@ -0,0 +1,66 @@ +/* reacTIVision tangible interaction framework + Copyright (C) 2005-2016 Martin Kaltenbrunner + Based on an example by Nicolas Roussel + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "OneEuroFilter.h" +#define M_PI 3.14159265392 + +using namespace TUIO; + +double LowPassFilter::filter(double value, double alpha) { + + if (alpha<=0.0 || alpha>1.0) + throw std::range_error("alpha should be in (0.0., 1.0]"); + + double result; + if (initialized) + result = alpha*value + (1.0-alpha)*lastResult; + else { + result = value; + initialized = true; + } + + lastRawValue = value; + lastResult = result; + return result; +} + +// ----------------------------------------------------------------- + +double OneEuroFilter::alpha(double cutoff) { + double te = 1.0 / freq; + double tau = 1.0 / (2*M_PI*cutoff); + return 1.0 / (1.0 + tau/te); +} + +double OneEuroFilter::filter(double value, TimeStamp timestamp) { + // update the sampling frequency based on timestamps + if (lasttime!=UndefinedTime && timestamp!=UndefinedTime) + freq = 1.0 / (timestamp-lasttime); + lasttime = timestamp; + // estimate the current variation per second + double dvalue = x->initialized ? (value - x->lastRawValue)*freq : value; + + double edvalue; + try { edvalue = dx->filter(dvalue, alpha(dcutoff)); + } catch (std::range_error e) { return value; } + // use it to update the cutoff frequency + double cutoff = mincutoff + beta*fabs(edvalue); + // filter the given value + return x->filter(value, alpha(cutoff)); +} \ No newline at end of file diff --git a/modules/touch/ext/libTUIO/TUIO/OneEuroFilter.h b/modules/touch/ext/libTUIO/TUIO/OneEuroFilter.h new file mode 100644 index 0000000000..7fc4ee16ad --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/OneEuroFilter.h @@ -0,0 +1,90 @@ +/* reacTIVision tangible interaction framework + Copyright (C) 2005-2016 Martin Kaltenbrunner + Based on an example by Nicolas Roussel + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ONEEUROFILTER +#define ONEEUROFILTER + +#include +#include + +typedef double TimeStamp; // in seconds +static const TimeStamp UndefinedTime = -1.0; + +namespace TUIO { + + class LowPassFilter { + + public: + + bool initialized; + double lastRawValue,lastResult; + + LowPassFilter(double initval=0.0) { + + lastRawValue = lastResult = initval; + initialized = false; + } + + double filter(double value, double alpha); + }; + + // ----------------------------------------------------------------- + + class OneEuroFilter { + + double freq; + double mincutoff; + double beta; + double dcutoff; + LowPassFilter *x; + LowPassFilter *dx; + TimeStamp lasttime; + + double alpha(double cutoff); + + public: + + OneEuroFilter(double f, double mc=1.0, double b=0.0, double dc=1.0) { + + if (f<=0) throw std::range_error("freq should be >0"); + else freq = f; + if (mc<=0) throw std::range_error("mincutoff should be >0"); + else mincutoff = mc; + if (b<=0) throw std::range_error("beta should be >0"); + else beta = b; + if (dc<=0) throw std::range_error("dcutoff should be >0"); + else dcutoff = dc; + + x = new LowPassFilter(alpha(mincutoff)); + dx = new LowPassFilter(alpha(dcutoff)); + lasttime = UndefinedTime; + } + + ~OneEuroFilter(void) { + delete x; + delete dx; + } + + double filter(double value, TimeStamp timestamp=UndefinedTime); + + }; + +} + +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.cpp b/modules/touch/ext/libTUIO/TUIO/OscReceiver.cpp similarity index 89% rename from modules/touch/ext/libTUIO2/TUIO2/OscReceiver.cpp rename to modules/touch/ext/libTUIO/TUIO/OscReceiver.cpp index 0e9af08f47..d038b64bec 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.cpp +++ b/modules/touch/ext/libTUIO/TUIO/OscReceiver.cpp @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,15 +18,15 @@ #include "OscReceiver.h" -using namespace TUIO2; +using namespace TUIO; using namespace osc; void OscReceiver::ProcessMessage( const ReceivedMessage& msg, const IpEndpointName& remoteEndpoint) { - for (std::list::iterator client=clientList.begin(); client!= clientList.end(); client++) + for (std::list::iterator client=clientList.begin(); client!= clientList.end(); client++) (*client)->processOSC(msg); } - void OscReceiver::ProcessBundle( const ReceivedBundle& b, const IpEndpointName& remoteEndpoint) { + try { for( ReceivedBundle::const_iterator i = b.ElementsBegin(); i != b.ElementsEnd(); ++i ){ if( i->IsBundle() ) diff --git a/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.h b/modules/touch/ext/libTUIO/TUIO/OscReceiver.h similarity index 95% rename from modules/touch/ext/libTUIO2/TUIO2/OscReceiver.h rename to modules/touch/ext/libTUIO/TUIO/OscReceiver.h index b8bcd22743..716b347c82 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/OscReceiver.h +++ b/modules/touch/ext/libTUIO/TUIO/OscReceiver.h @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -27,7 +27,7 @@ #include "oscpack/ip/PacketListener.h" #include "oscpack/ip/IpEndpointName.h" -namespace TUIO2 { +namespace TUIO { class TuioClient; // Forward declaration @@ -35,7 +35,7 @@ namespace TUIO2 { * The OscReceiver is the base class for the various OSC transport methods such as UDP, TCP ... * * @author Martin Kaltenbrunner - * @version 2.0.a0 + * @version 1.1.6 */ class LIBDECL OscReceiver: public PacketListener { diff --git a/modules/touch/ext/libTUIO2/TUIO2/OscSender.h b/modules/touch/ext/libTUIO/TUIO/OscSender.h similarity index 97% rename from modules/touch/ext/libTUIO2/TUIO2/OscSender.h rename to modules/touch/ext/libTUIO/TUIO/OscSender.h index 967941ca5b..37d13a8d22 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/OscSender.h +++ b/modules/touch/ext/libTUIO/TUIO/OscSender.h @@ -1,5 +1,5 @@ /* - TUIO2 C++ Library + TUIO C++ Library Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or @@ -26,14 +26,14 @@ #include #include -namespace TUIO2 { +namespace TUIO { /** * The OscSender class is the base class for the various OSC transport methods such as UDP, TCP ... * * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ + * @version 1.1.6 + */ class LIBDECL OscSender { public: diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp b/modules/touch/ext/libTUIO/TUIO/TcpReceiver.cpp similarity index 92% rename from modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp rename to modules/touch/ext/libTUIO/TUIO/TcpReceiver.cpp index ba0a5f4c65..a205225ef3 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.cpp +++ b/modules/touch/ext/libTUIO/TUIO/TcpReceiver.cpp @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ #include "TcpReceiver.h" -using namespace TUIO2; +using namespace TUIO; using namespace osc; // workaround for connect method name conflict @@ -39,6 +39,7 @@ static void* ClientThreadFunc( void* obj ) TcpReceiver *sender = static_cast(obj); char data_buffer[MAX_TCP_SIZE+4]; char data_size[4]; + int32_t bundle_size; #ifdef WIN32 SOCKET client = sender->tcp_client_list.back(); @@ -53,15 +54,15 @@ static void* ClientThreadFunc( void* obj ) if (bytes>=4) { memcpy(&data_size[0],&data_buffer[0], 4); #ifdef OSC_HOST_LITTLE_ENDIAN - int32_t temp = (int32_t)(*data_size); - data_size[0] = temp>>24; - data_size[1] = (temp>>16) & 255; - data_size[2] = (temp>>8) & 255; - data_size[3] = (temp) & 255; + bundle_size = 0xFF & data_size[3]; + bundle_size |= (0xFF & data_size[2]) << 8; + bundle_size |= (0xFF & data_size[1]) << 16; + bundle_size |= (int32_t)(0xFF & data_size[0]) << 24; +#else + bundle_size = (int32_t)(*data_size); #endif - int32_t size = (int32_t)(*data_size); - if (size+4==bytes) { - sender->ProcessPacket(&data_buffer[4],(int)size,IpEndpointName()); + if (bundle_size+4==bytes) { + sender->ProcessPacket(&data_buffer[4],(int)bundle_size,IpEndpointName()); } } } @@ -113,7 +114,7 @@ static DWORD WINAPI ServerThreadFunc( LPVOID obj ) return 0; }; -TcpReceiver::TcpReceiver(unsigned short port) +TcpReceiver::TcpReceiver(int port) : tcp_socket (-1) , locked (false) { @@ -161,7 +162,7 @@ TcpReceiver::TcpReceiver(unsigned short port) std::cout << "TUIO/TCP socket created on port " << port << std::endl; } -TcpReceiver::TcpReceiver(const char *host, unsigned short port) +TcpReceiver::TcpReceiver(const char *host, int port) : tcp_socket (-1) , locked (false) { diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.h b/modules/touch/ext/libTUIO/TUIO/TcpReceiver.h similarity index 91% rename from modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.h rename to modules/touch/ext/libTUIO/TUIO/TcpReceiver.h index 75816b5e8e..bd3e6f9b89 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TcpReceiver.h +++ b/modules/touch/ext/libTUIO/TUIO/TcpReceiver.h @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -35,13 +35,13 @@ typedef int socklen_t; #include #endif -namespace TUIO2 { +namespace TUIO { /** * The TcpReceiver provides the OscReceiver functionality for the TCP transport method * * @author Martin Kaltenbrunner - * @version 2.0.a0 + * @version 1.1.6 */ class LIBDECL TcpReceiver: public OscReceiver { @@ -52,7 +52,7 @@ namespace TUIO2 { * * @param port the number of the TCP port to listen to, defaults to 3333 */ - TcpReceiver (unsigned short port=3333); + TcpReceiver (int port=3333); /** * This constructor creates a TcpReceiver connected to the provided host and TCP port @@ -60,7 +60,7 @@ namespace TUIO2 { * @param host the host name to connect * @param port the number of the TCP port to listen to, defaults to 3333 */ - TcpReceiver (const char *host, unsigned short port); + TcpReceiver (const char *host, int port); /** * The destructor is doing nothing in particular. diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpSender.cpp b/modules/touch/ext/libTUIO/TUIO/TcpSender.cpp similarity index 99% rename from modules/touch/ext/libTUIO2/TUIO2/TcpSender.cpp rename to modules/touch/ext/libTUIO/TUIO/TcpSender.cpp index d6a3acc597..a232d747a3 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TcpSender.cpp +++ b/modules/touch/ext/libTUIO/TUIO/TcpSender.cpp @@ -17,7 +17,7 @@ */ #include "TcpSender.h" -using namespace TUIO2; +using namespace TUIO; #ifndef WIN32 static void* ClientThreadFunc( void* obj ) diff --git a/modules/touch/ext/libTUIO2/TUIO2/TcpSender.h b/modules/touch/ext/libTUIO/TUIO/TcpSender.h similarity index 99% rename from modules/touch/ext/libTUIO2/TUIO2/TcpSender.h rename to modules/touch/ext/libTUIO/TUIO/TcpSender.h index 03b8678048..acef5ab03f 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TcpSender.h +++ b/modules/touch/ext/libTUIO/TUIO/TcpSender.h @@ -37,14 +37,14 @@ typedef int socklen_t; #include #define MAX_TCP_SIZE 65536 -namespace TUIO2 { +namespace TUIO { /** * The TcpSender implements the TCP transport method for OSC * * @author Martin Kaltenbrunner * @version 2.0.a0 - */ + */ class LIBDECL TcpSender : public OscSender { public: diff --git a/modules/touch/ext/libTUIO/TUIO/TuioBlob.cpp b/modules/touch/ext/libTUIO/TUIO/TuioBlob.cpp new file mode 100644 index 0000000000..124603f50a --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioBlob.cpp @@ -0,0 +1,253 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioBlob.h" +using namespace TUIO; + +TuioBlob::TuioBlob (TuioTime ttime, long si, int bi, float xp, float yp, float a, float w, float h, float f):TuioContainer(ttime, si, xp, yp) { + blob_id = bi; + angle = a; + angle_sum = a; + width = w; + height = h; + area = f; + rotation_speed = 0.0f; + rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; + widthFilter = NULL; + heightFilter = NULL; + sizeThreshold = 0.0f; +} + +TuioBlob::TuioBlob (long si, int bi, float xp, float yp, float a, float w, float h, float f):TuioContainer(si, xp, yp) { + blob_id = bi; + angle = a; + angle_sum = a; + width = w; + height = h; + area = f; + rotation_speed = 0.0f; + rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; + widthFilter = NULL; + heightFilter = NULL; + sizeThreshold = 0.0f; +} + +TuioBlob::TuioBlob (TuioBlob *tblb):TuioContainer(tblb) { + blob_id = tblb->getBlobID(); + angle = tblb->getAngle(); + angle_sum = tblb->getAngleSum(); + width = tblb->getWidth(); + height = tblb->getHeight(); + area = tblb->getArea(); + rotation_speed = 0.0f; + rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; + widthFilter = NULL; + heightFilter = NULL; + sizeThreshold = 0.0f; +} + +int TuioBlob::getBlobID() const{ + return blob_id; +} + +void TuioBlob::setBlobID(long b_id) { + blob_id = b_id; +} + +void TuioBlob::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { + TuioContainer::update(ttime,xp,yp,xs,ys,ma); + angle = a; + angle_sum = a; + width = w; + height = h; + area = f; + rotation_speed = rs; + rotation_accel = ra; + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + +void TuioBlob::update (float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { + TuioContainer::update(xp,yp,xs,ys,ma); + angle = a; + angle_sum = a; + width = w; + height = h; + area = f; + rotation_speed = rs; + rotation_accel = ra; + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + +void TuioBlob::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f) { + TuioPoint lastPoint = path.back(); + TuioContainer::update(ttime,xp,yp); + + TuioTime diffTime = currentTime - lastPoint.getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + float last_rotation_speed = rotation_speed; + + float prev_angle = angle_sum; + float da = a-angle; + if (da > M_PI/2.0f) angle_sum += (da-2*M_PI); + else if (da < M_PI/-2.0f) angle_sum += (da+2*M_PI); + else angle_sum += da; + + if (angleFilter) angle_sum = angleFilter->filter(angle_sum,dt); + if (fabs(angle_sum-prev_angle) 0.75f) da-=1.0f; + else if (da < -0.75f) da+=1.0f; + + if (widthFilter && heightFilter) { + w = widthFilter->filter(w,dt); + h = heightFilter->filter(h,dt); + } + + float dw = fabs(width - w); + float dh = fabs(height - h); + if ((dw>sizeThreshold) || (dh>sizeThreshold)) { + width = w; + height = h; + } + + area = f; + + rotation_speed = (float)da/dt; + rotation_accel = (rotation_speed - last_rotation_speed)/dt; + + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + +void TuioBlob::stop (TuioTime ttime) { + update(ttime,xpos,ypos,angle,width,height,area); +} + +void TuioBlob::update (TuioBlob *tblb) { + TuioContainer::update(tblb); + angle = tblb->getAngle(); + angle = tblb->getAngleSum(); + width = tblb->getWidth(); + height = tblb->getHeight(); + area = tblb->getArea(); + rotation_speed = tblb->getRotationSpeed(); + rotation_accel = tblb->getRotationAccel(); + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + +float TuioBlob::getWidth() const{ + return width; +} + +float TuioBlob::getHeight() const{ + return height; +} + +int TuioBlob::getScreenWidth(int w) const{ + return (int)(w*width); +} + +int TuioBlob::getScreenHeight(int h) const{ + return (int)(h*height); +} + +float TuioBlob::getArea() const{ + return area; +} + +float TuioBlob::getAngle() const{ + return angle; +} + +float TuioBlob::getAngleSum() const{ + return angle_sum; +} + +float TuioBlob::getAngleDegrees() const{ + return (float)(angle/M_PI*180); +} + +float TuioBlob::getRotationSpeed() const{ + return rotation_speed; +} + +float TuioBlob::getRotationAccel() const{ + return rotation_accel; +} + +bool TuioBlob::isMoving() const{ + if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true; + else return false; +} + +void TuioBlob::addAngleThreshold(float thresh) { + angleThreshold = thresh; +} + +void TuioBlob::removeAngleThreshold() { + angleThreshold = 0.0f; +} + +void TuioBlob::addAngleFilter(float mcut, float beta) { + + if (angleFilter) delete angleFilter; + angleFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioBlob::removeAngleFilter() { + + if (angleFilter) delete angleFilter; + angleFilter = NULL; +} + +void TuioBlob::addSizeThreshold(float thresh) { + sizeThreshold = thresh; +} + +void TuioBlob::removeSizeThreshold() { + sizeThreshold = 0.0f; +} + +void TuioBlob::addSizeFilter(float mcut, float beta) { + + if (widthFilter) delete widthFilter; + widthFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); + if (heightFilter) delete heightFilter; + heightFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioBlob::removeSizeFilter() { + + if (widthFilter) delete widthFilter; + widthFilter = NULL; + if (heightFilter) delete heightFilter; + heightFilter = NULL; +} + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h b/modules/touch/ext/libTUIO/TUIO/TuioBlob.h similarity index 51% rename from modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h rename to modules/touch/ext/libTUIO/TUIO/TuioBlob.h index 803f67c3b7..3301e8c3d3 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.h +++ b/modules/touch/ext/libTUIO/TUIO/TuioBlob.h @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,27 +16,34 @@ License along with this library. */ -#ifndef INCLUDED_TUIOBOUNDS_H -#define INCLUDED_TUIOBOUNDS_H +#ifndef INCLUDED_TUIOBLOB_H +#define INCLUDED_TUIOBLOB_H -#include "TuioComponent.h" +#include "TuioContainer.h" -namespace TUIO2 { +namespace TUIO { /** - * The TuioBounds class encapsulates /tuio2/bnd TUIO boundary ellipses. + * The TuioBlob class encapsulates /tuio/2Dblb TUIO objects. * * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - - class LIBDECL TuioBounds: public TuioComponent { + * @version 1.1.6 + */ + class LIBDECL TuioBlob: public TuioContainer { protected: + /** + * The individual blob ID number that is assigned to each TuioBlob. + */ + int blob_id; /** * The rotation angle value. */ float angle; + /** + * The accumulated angle value. + */ + float angle_sum; /** * The width value. */ @@ -58,15 +65,21 @@ namespace TUIO2 { */ float rotation_accel; - public: - using TuioComponent::update; + float angleThreshold; + OneEuroFilter *angleFilter; + float sizeThreshold; + OneEuroFilter *widthFilter; + OneEuroFilter *heightFilter; + public: + using TuioContainer::update; + /** * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, X and Y coordinate, width, height and angle to the newly created TuioBounds. + * Session ID, X and Y coordinate, width, height and angle to the newly created TuioBlob. * * @param ttime the TuioTime to assign - * @param tobj the TuioObject to assign + * @param si the Session ID to assign * @param xp the X coordinate to assign * @param yp the Y coordinate to assign * @param a the angle to assign @@ -74,39 +87,55 @@ namespace TUIO2 { * @param h the height to assign * @param f the area to assign */ - TuioBounds (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a, float w, float h, float f); - - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, X and Y coordinate, width, height and angle to the newly created TuioBounds. - * - * @param tobj the TuioObject to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @param w the width to assign - * @param h the height to assign - * @param f the area to assign - */ - TuioBounds (TuioObject *tobj, float xp, float yp, float a, float w, float h, float f); + TuioBlob (TuioTime ttime, long si, int bi, float xp, float yp, float a, float w, float h, float f); + + /** + * This constructor takes the provided Session ID, X and Y coordinate + * width, height and angle, and assigs these values to the newly created TuioBlob. + * + * @param si the Session ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @param w the width to assign + * @param h the height to assign + * @param f the area to assign + */ + TuioBlob (long si, int bi, float xp, float yp, float a, float w, float h, float f); /** - * This constructor takes the atttibutes of the provided TuioBounds - * and assigs these values to the newly created TuioBounds. + * This constructor takes the atttibutes of the provided TuioBlob + * and assigs these values to the newly created TuioBlob. * - * @param tbnd the TuioBounds to assign + * @param tblb the TuioBlob to assign */ - TuioBounds (TuioBounds *tbnd); + TuioBlob (TuioBlob *tblb); /** * The destructor is doing nothing in particular. */ - ~TuioBounds() {}; + virtual ~TuioBlob() { + if (widthFilter) delete widthFilter; + if (heightFilter) delete heightFilter; + if (angleFilter) delete angleFilter; + }; + + /** + * Returns the Blob ID of this TuioBlob. + * @return the Blob ID of this TuioBlob + */ + int getBlobID() const; + + /** + * Sets the Blob ID of this TuioBlob. + * @param b_id the new Blob ID for this TuioBlob + */ + void setBlobID(long b_id); /** * Takes a TuioTime argument and assigns it along with the provided * X and Y coordinate, angle, X and Y velocity, motion acceleration, - * rotation speed and rotation acceleration to the private TuioBounds attributes. + * rotation speed and rotation acceleration to the private TuioBlob attributes. * * @param ttime the TuioTime to assign * @param xp the X coordinate to assign @@ -125,7 +154,7 @@ namespace TUIO2 { /** * Assigns the provided X and Y coordinate, angle, X and Y velocity, motion acceleration - * rotation velocity and rotation acceleration to the private TuioComponent attributes. + * rotation velocity and rotation acceleration to the private TuioContainer attributes. * The TuioTime time stamp remains unchanged. * * @param xp the X coordinate to assign @@ -144,7 +173,7 @@ namespace TUIO2 { /** * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate and angle to the private TuioBounds attributes. + * X and Y coordinate and angle to the private TuioBlob attributes. * The speed and accleration values are calculated accordingly. * * @param ttime the TuioTime to assign @@ -159,48 +188,100 @@ namespace TUIO2 { /** * This method is used to calculate the speed and acceleration values of a - * TuioBounds with unchanged position and angle. + * TuioBlob with unchanged position and angle. */ void stop (TuioTime ttime); /** - * Takes the atttibutes of the provided TuioBounds - * and assigs these values to this TuioBounds. - * The TuioTime time stamp of this TuioComponent remains unchanged. + * Takes the atttibutes of the provided TuioBlob + * and assigs these values to this TuioBlob. + * The TuioTime time stamp of this TuioContainer remains unchanged. * - * @param tbnd the TuioComponent to assign + * @param tblb the TuioContainer to assign */ - void update (TuioBounds *tbnd); + void update (TuioBlob *tblb); /** - * Returns the width of this TuioBounds. - * @return the width of this TuioBounds + * Returns the width of this TuioBlob. + * @return the width of this TuioBlob */ float getWidth() const; /** - * Returns the height of this TuioBounds. - * @return the height of this TuioBounds + * Returns the height of this TuioBlob. + * @return the height of this TuioBlob */ float getHeight() const; /** - * Returns the width of this TuioBounds. - * @return the width of this TuioBounds + * Returns the width of this TuioBlob. + * @return the width of this TuioBlob */ int getScreenWidth(int w) const; /** - * Returns the height of this TuioBounds. - * @return the height of this TuioBounds + * Returns the height of this TuioBlob. + * @return the height of this TuioBlob */ int getScreenHeight(int h) const; /** - * Returns the area of this TuioBounds. - * @return the area of this TuioBounds + * Returns the area of this TuioBlob. + * @return the area of this TuioBlob */ float getArea() const; + + /** + * Returns the rotation angle of this TuioBlob. + * @return the rotation angle of this TuioBlob + */ + float getAngle() const; + + /** + * Returns the accumulated rotation angle of this TuioBlob. + * @return the accumulated rotation angle of this TuioBlob + */ + float getAngleSum() const; + + /** + * Returns the rotation angle in degrees of this TuioBlob. + * @return the rotation angle in degrees of this TuioBlob + */ + float getAngleDegrees() const; + + /** + * Returns the rotation speed of this TuioBlob. + * @return the rotation speed of this TuioBlob + */ + float getRotationSpeed() const; + + /** + * Returns the rotation acceleration of this TuioBlob. + * @return the rotation acceleration of this TuioBlob + */ + float getRotationAccel() const; + + /** + * Returns true of this TuioBlob is moving. + * @return true of this TuioBlob is moving + */ + bool isMoving() const; + + void addAngleThreshold(float thresh); + + void removeAngleThreshold(); + + void addAngleFilter(float mcut, float beta); + + void removeAngleFilter(); + + void addSizeThreshold(float thresh); + + void removeSizeThreshold(); + + void addSizeFilter(float mcut, float beta); + + void removeSizeFilter(); }; } #endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioClient.cpp b/modules/touch/ext/libTUIO/TUIO/TuioClient.cpp new file mode 100644 index 0000000000..43a93bef46 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioClient.cpp @@ -0,0 +1,849 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioClient.h" +#include "UdpReceiver.h" + +using namespace TUIO; +using namespace osc; + + +TuioClient::TuioClient() +: currentFrame (-1) +, source_id (0) +, source_name (NULL) +, source_addr (NULL) +, local_receiver(true) +{ + receiver = new UdpReceiver(); + initialize(); +} + +TuioClient::TuioClient(int port) +: currentFrame (-1) +, source_id (0) +, source_name (NULL) +, source_addr (NULL) +, local_receiver(true) +{ + receiver = new UdpReceiver(port); + initialize(); +} + +TuioClient::TuioClient(OscReceiver *osc) +: currentFrame (-1) +, source_id (0) +, source_name (NULL) +, source_addr (NULL) +, receiver (osc) +, local_receiver(false) +{ + initialize(); +} + +void TuioClient::initialize() { + receiver->addTuioClient(this); + maxCursorID[source_id] = -1; + maxBlobID[source_id] = -1; +} + +TuioClient::~TuioClient() { + if (local_receiver) delete receiver; +} + +void TuioClient::processOSC( const ReceivedMessage& msg ) { + try { + ReceivedMessageArgumentStream args = msg.ArgumentStream(); + //ReceivedMessage::const_iterator arg = msg.ArgumentsBegin(); + + if( strcmp( msg.AddressPattern(), "/tuio/2Dobj" ) == 0 ){ + + const char* cmd; + args >> cmd; + + if (strcmp(cmd,"source")==0) { + const char* src; + args >> src; + + source_name = strtok((char*)src, "@"); + char *addr = strtok(NULL, "@"); + + if (addr!=NULL) source_addr = addr; + else source_addr = (char*)"localhost"; + + // check if we know that source + std::string source_str(src); + std::map::iterator iter = sourceList.find(source_str); + + // add a new source + if (iter==sourceList.end()) { + source_id = sourceList.size(); + sourceList[source_str] = source_id; + } else { + // use the found source_id + source_id = sourceList[source_str]; + } + + } else if (strcmp(cmd,"set")==0) { + int32 s_id, c_id; + float xpos, ypos, angle, xspeed, yspeed, rspeed, maccel, raccel; + args >> s_id >> c_id >> xpos >> ypos >> angle >> xspeed >> yspeed >> rspeed >> maccel >> raccel; + + lockObjectList(); + std::list::iterator tobj; + for (tobj=objectList.begin(); tobj!= objectList.end(); tobj++) + if((*tobj)->getSessionID()==(long)s_id) break; + + if (tobj == objectList.end()) { + + TuioObject *addObject = new TuioObject((long)s_id,(int)c_id,xpos,ypos,angle); + frameObjects.push_back(addObject); + + } else if ( ((*tobj)->getX()!=xpos) || ((*tobj)->getY()!=ypos) || ((*tobj)->getAngle()!=angle) || ((*tobj)->getXSpeed()!=xspeed) || ((*tobj)->getYSpeed()!=yspeed) || ((*tobj)->getRotationSpeed()!=rspeed) || ((*tobj)->getMotionAccel()!=maccel) || ((*tobj)->getRotationAccel()!=raccel) ) { + + TuioObject *updateObject = new TuioObject((long)s_id,(*tobj)->getSymbolID(),xpos,ypos,angle); + updateObject->update(xpos,ypos,angle,xspeed,yspeed,rspeed,maccel,raccel); + frameObjects.push_back(updateObject); + + } + unlockObjectList(); + + } else if (strcmp(cmd,"alive")==0) { + + int32 s_id; + aliveObjectList.clear(); + while(!args.Eos()) { + args >> s_id; + aliveObjectList.push_back((long)s_id); + } + + } else if (strcmp(cmd,"fseq")==0) { + + int32 fseq; + args >> fseq; + bool lateFrame = false; + if (fseq>0) { + if (fseq>currentFrame) currentTime = TuioTime::getSessionTime(); + if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq; + else lateFrame = true; + } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) { + currentTime = TuioTime::getSessionTime(); + } + + if (!lateFrame) { + + lockObjectList(); + //find the removed objects first + for (std::list::iterator tobj=objectList.begin(); tobj != objectList.end(); tobj++) { + if ((*tobj)->getTuioSourceID()==source_id) { + std::list::iterator iter = find(aliveObjectList.begin(), aliveObjectList.end(), (*tobj)->getSessionID()); + if (iter == aliveObjectList.end()) { + (*tobj)->remove(currentTime); + frameObjects.push_back(*tobj); + } + } + } + unlockObjectList(); + + for (std::list::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) { + TuioObject *tobj = (*iter); + + TuioObject *frameObject = NULL; + switch (tobj->getTuioState()) { + case TUIO_REMOVED: + + frameObject = tobj; + frameObject->remove(currentTime); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioObject(frameObject); + + lockObjectList(); + for (std::list::iterator delobj=objectList.begin(); delobj!=objectList.end(); delobj++) { + if((*delobj)->getSessionID()==frameObject->getSessionID()) { + objectList.erase(delobj); + break; + } + } + unlockObjectList(); + break; + case TUIO_ADDED: + + lockObjectList(); + frameObject = new TuioObject(currentTime,tobj->getSessionID(),tobj->getSymbolID(),tobj->getX(),tobj->getY(),tobj->getAngle()); + if (source_name) frameObject->setTuioSource(source_id,source_name,source_addr); + objectList.push_back(frameObject); + unlockObjectList(); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioObject(frameObject); + + break; + default: + + lockObjectList(); + std::list::iterator iter; + for (iter=objectList.begin(); iter != objectList.end(); iter++) { + if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tobj->getSessionID())) { + frameObject = (*iter); + break; + } + } + + if (iter==objectList.end()) { + unlockObjectList(); + break; + } + + if ( (tobj->getX()!=frameObject->getX() && tobj->getXSpeed()==0) || (tobj->getY()!=frameObject->getY() && tobj->getYSpeed()==0) ) + frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle()); + else + frameObject->update(currentTime,tobj->getX(),tobj->getY(),tobj->getAngle(),tobj->getXSpeed(),tobj->getYSpeed(),tobj->getRotationSpeed(),tobj->getMotionAccel(),tobj->getRotationAccel()); + + unlockObjectList(); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioObject(frameObject); + } + delete tobj; + } + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->refresh(currentTime); + + } else { + for (std::list::iterator iter=frameObjects.begin(); iter != frameObjects.end(); iter++) { + TuioObject *tobj = (*iter); + delete tobj; + } + } + + frameObjects.clear(); + } + } else if( strcmp( msg.AddressPattern(), "/tuio/2Dcur" ) == 0 ) { + const char* cmd; + args >> cmd; + + if (strcmp(cmd,"source")==0) { + const char* src; + args >> src; + + source_name = strtok((char*)src, "@"); + char *addr = strtok(NULL, "@"); + + if (addr!=NULL) source_addr = addr; + else source_addr = (char*)"localhost"; + + // check if we know that source + std::string source_str(src); + std::map::iterator iter = sourceList.find(source_str); + + // add a new source + if (iter==sourceList.end()) { + source_id = sourceList.size(); + sourceList[source_str] = source_id; + maxCursorID[source_id] = -1; + } else { + // use the found source_id + source_id = sourceList[source_str]; + } + + } else if (strcmp(cmd,"set")==0) { + + int32 s_id; + float xpos, ypos, xspeed, yspeed, maccel; + args >> s_id >> xpos >> ypos >> xspeed >> yspeed >> maccel; + + lockCursorList(); + std::list::iterator tcur; + for (tcur=cursorList.begin(); tcur!= cursorList.end(); tcur++) + if (((*tcur)->getSessionID()==(long)s_id) && ((*tcur)->getTuioSourceID()==source_id)) break; + + if (tcur==cursorList.end()) { + + TuioCursor *addCursor = new TuioCursor((long)s_id,-1,xpos,ypos); + frameCursors.push_back(addCursor); + + } else if ( ((*tcur)->getX()!=xpos) || ((*tcur)->getY()!=ypos) || ((*tcur)->getXSpeed()!=xspeed) || ((*tcur)->getYSpeed()!=yspeed) || ((*tcur)->getMotionAccel()!=maccel) ) { + + TuioCursor *updateCursor = new TuioCursor((long)s_id,(*tcur)->getCursorID(),xpos,ypos); + updateCursor->update(xpos,ypos,xspeed,yspeed,maccel); + frameCursors.push_back(updateCursor); + + } + unlockCursorList(); + + } else if (strcmp(cmd,"alive")==0) { + + int32 s_id; + aliveCursorList.clear(); + while(!args.Eos()) { + args >> s_id; + aliveCursorList.push_back((long)s_id); + } + + } else if( strcmp( cmd, "fseq" ) == 0 ) { + int32 fseq; + args >> fseq; + bool lateFrame = false; + if (fseq>0) { + if (fseq>currentFrame) currentTime = TuioTime::getSessionTime(); + if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq; + else lateFrame = true; + } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) { + currentTime = TuioTime::getSessionTime(); + } + + if (!lateFrame) { + + lockCursorList(); + // find the removed cursors first + for (std::list::iterator tcur=cursorList.begin(); tcur != cursorList.end(); tcur++) { + if ((*tcur)->getTuioSourceID()==source_id) { + std::list::iterator iter = find(aliveCursorList.begin(), aliveCursorList.end(), (*tcur)->getSessionID()); + + if (iter == aliveCursorList.end()) { + (*tcur)->remove(currentTime); + frameCursors.push_back(*tcur); + } + } + } + unlockCursorList(); + + for (std::list::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) { + TuioCursor *tcur = (*iter); + + int c_id = 0; + int free_size = 0; + TuioCursor *frameCursor = NULL; + switch (tcur->getTuioState()) { + case TUIO_REMOVED: + + frameCursor = tcur; + frameCursor->remove(currentTime); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioCursor(frameCursor); + + lockCursorList(); + for (std::list::iterator delcur=cursorList.begin(); delcur!=cursorList.end(); delcur++) { + if(((*delcur)->getTuioSourceID()==source_id) && ((*delcur)->getSessionID()==frameCursor->getSessionID())) { + cursorList.erase(delcur); + break; + } + } + + if (frameCursor->getCursorID()==maxCursorID[source_id]) { + maxCursorID[source_id] = -1; + delete frameCursor; + + if (cursorList.size()>0) { + std::list::iterator clist; + for (clist=cursorList.begin(); clist != cursorList.end(); clist++) { + if ((*clist)->getTuioSourceID()==source_id) { + c_id = (*clist)->getCursorID(); + if (c_id>maxCursorID[source_id]) maxCursorID[source_id]=c_id; + } + } + + freeCursorBuffer.clear(); + for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { + TuioCursor *freeCursor = (*flist); + if (freeCursor->getTuioSourceID()==source_id) { + if (freeCursor->getCursorID()>maxCursorID[source_id]) delete freeCursor; + else freeCursorBuffer.push_back(freeCursor); + } else freeCursorBuffer.push_back(freeCursor); + } + freeCursorList = freeCursorBuffer; + + } else { + freeCursorBuffer.clear(); + for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { + TuioCursor *freeCursor = (*flist); + if (freeCursor->getTuioSourceID()==source_id) delete freeCursor; + else freeCursorBuffer.push_back(freeCursor); + } + freeCursorList = freeCursorBuffer; + + } + } else if (frameCursor->getCursorID()::iterator iter = cursorList.begin();iter!= cursorList.end(); iter++) + if ((*iter)->getTuioSourceID()==source_id) c_id++; + + for(std::list::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) + if ((*iter)->getTuioSourceID()==source_id) free_size++; + + if ((free_size<=maxCursorID[source_id]) && (free_size>0)) { + std::list::iterator closestCursor = freeCursorList.begin(); + + for(std::list::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) { + if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getDistance(tcur)<(*closestCursor)->getDistance(tcur))) closestCursor = iter; + } + + if (closestCursor!=freeCursorList.end()) { + TuioCursor *freeCursor = (*closestCursor); + c_id = freeCursor->getCursorID(); + freeCursorList.erase(closestCursor); + delete freeCursor; + } + } else maxCursorID[source_id] = c_id; + + frameCursor = new TuioCursor(currentTime,tcur->getSessionID(),c_id,tcur->getX(),tcur->getY()); + if (source_name) frameCursor->setTuioSource(source_id,source_name,source_addr); + cursorList.push_back(frameCursor); + + delete tcur; + unlockCursorList(); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioCursor(frameCursor); + + break; + default: + + lockCursorList(); + std::list::iterator iter; + for (iter=cursorList.begin(); iter != cursorList.end(); iter++) { + if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tcur->getSessionID())) { + frameCursor = (*iter); + break; + } + } + + if (iter==cursorList.end()) { + unlockCursorList(); + break; + } + + if ( (tcur->getX()!=frameCursor->getX() && tcur->getXSpeed()==0) || (tcur->getY()!=frameCursor->getY() && tcur->getYSpeed()==0) ) + frameCursor->update(currentTime,tcur->getX(),tcur->getY()); + else + frameCursor->update(currentTime,tcur->getX(),tcur->getY(),tcur->getXSpeed(),tcur->getYSpeed(),tcur->getMotionAccel()); + + delete tcur; + unlockCursorList(); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioCursor(frameCursor); + + } + } + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->refresh(currentTime); + + } else { + for (std::list::iterator iter=frameCursors.begin(); iter != frameCursors.end(); iter++) { + TuioCursor *tcur = (*iter); + delete tcur; + } + } + + frameCursors.clear(); + } + } else if( strcmp( msg.AddressPattern(), "/tuio/2Dblb" ) == 0 ){ + const char* cmd; + args >> cmd; + + if (strcmp(cmd,"source")==0) { + const char* src; + args >> src; + + source_name = strtok((char*)src, "@"); + char *addr = strtok(NULL, "@"); + + if (addr!=NULL) source_addr = addr; + else source_addr = (char*)"localhost"; + + // check if we know that source + std::string source_str(src); + std::map::iterator iter = sourceList.find(source_str); + + // add a new source + if (iter==sourceList.end()) { + source_id = sourceList.size(); + sourceList[source_str] = source_id; + maxBlobID[source_id] = -1; + } else { + // use the found source_id + source_id = sourceList[source_str]; + } + + } else if (strcmp(cmd,"set")==0) { + + int32 s_id; + float xpos, ypos, angle, width, height, area, xspeed, yspeed, rspeed, maccel, raccel; + args >> s_id >> xpos >> ypos >> angle >> width >> height >> area >> xspeed >> yspeed >> rspeed >> maccel >> raccel; + + lockBlobList(); + std::list::iterator tblb; + for (tblb=blobList.begin(); tblb!= blobList.end(); tblb++) + if((*tblb)->getSessionID()==(long)s_id) break; + + if (tblb==blobList.end()) { + + TuioBlob *addBlob = new TuioBlob((long)s_id,-1,xpos,ypos,angle,width,height,area); + frameBlobs.push_back(addBlob); + + } else if ( ((*tblb)->getX()!=xpos) || ((*tblb)->getY()!=ypos) || ((*tblb)->getAngle()!=angle) || ((*tblb)->getWidth()!=width) || ((*tblb)->getHeight()!=height) || ((*tblb)->getArea()!=area) || ((*tblb)->getXSpeed()!=xspeed) || ((*tblb)->getYSpeed()!=yspeed) || ((*tblb)->getMotionAccel()!=maccel) ) { + + TuioBlob *updateBlob = new TuioBlob((long)s_id,(*tblb)->getBlobID(),xpos,ypos,angle,width,height,area); + updateBlob->update(xpos,ypos,angle,width,height,area,xspeed,yspeed,rspeed,maccel,raccel); + frameBlobs.push_back(updateBlob); + } + unlockBlobList(); + + } else if (strcmp(cmd,"alive")==0) { + + int32 s_id; + aliveBlobList.clear(); + while(!args.Eos()) { + args >> s_id; + aliveBlobList.push_back((long)s_id); + } + + } else if( strcmp( cmd, "fseq" ) == 0 ) { + + int32 fseq; + args >> fseq; + bool lateFrame = false; + if (fseq>0) { + if (fseq>currentFrame) currentTime = TuioTime::getSessionTime(); + if ((fseq>=currentFrame) || ((currentFrame-fseq)>100)) currentFrame = fseq; + else lateFrame = true; + } else if ((TuioTime::getSessionTime().getTotalMilliseconds()-currentTime.getTotalMilliseconds())>100) { + currentTime = TuioTime::getSessionTime(); + } + + if (!lateFrame) { + + lockBlobList(); + // find the removed blobs first + for (std::list::iterator tblb=blobList.begin(); tblb != blobList.end(); tblb++) { + if ((*tblb)->getTuioSourceID()==source_id) { + std::list::iterator iter = find(aliveBlobList.begin(), aliveBlobList.end(), (*tblb)->getSessionID()); + + if (iter == aliveBlobList.end()) { + (*tblb)->remove(currentTime); + frameBlobs.push_back(*tblb); + } + } + } + unlockBlobList(); + + for (std::list::iterator iter=frameBlobs.begin(); iter != frameBlobs.end(); iter++) { + TuioBlob *tblb = (*iter); + + int b_id = 0; + int free_size = 0; + TuioBlob *frameBlob = NULL; + switch (tblb->getTuioState()) { + case TUIO_REMOVED: + frameBlob = tblb; + frameBlob->remove(currentTime); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioBlob(frameBlob); + + lockBlobList(); + for (std::list::iterator delblb=blobList.begin(); delblb!=blobList.end(); delblb++) { + if(((*delblb)->getTuioSourceID()==source_id) && ((*delblb)->getSessionID()==frameBlob->getSessionID())) { + blobList.erase(delblb); + break; + } + } + + if (frameBlob->getBlobID()==maxBlobID[source_id]) { + maxBlobID[source_id] = -1; + delete frameBlob; + + if (blobList.size()>0) { + std::list::iterator clist; + for (clist=blobList.begin(); clist != blobList.end(); clist++) { + if ((*clist)->getTuioSourceID()==source_id) { + b_id = (*clist)->getBlobID(); + if (b_id>maxBlobID[source_id]) maxBlobID[source_id]=b_id; + } + } + + freeBlobBuffer.clear(); + for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { + TuioBlob *freeBlob = (*flist); + if (freeBlob->getTuioSourceID()==source_id) { + if (freeBlob->getBlobID()>maxBlobID[source_id]) delete freeBlob; + else freeBlobBuffer.push_back(freeBlob); + } else freeBlobBuffer.push_back(freeBlob); + } + freeBlobList = freeBlobBuffer; + + } else { + freeBlobBuffer.clear(); + for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { + TuioBlob *freeBlob = (*flist); + if (freeBlob->getTuioSourceID()==source_id) delete freeBlob; + else freeBlobBuffer.push_back(freeBlob); + } + freeBlobList = freeBlobBuffer; + + } + } else if (frameBlob->getBlobID()::iterator iter = blobList.begin();iter!= blobList.end(); iter++) + if ((*iter)->getTuioSourceID()==source_id) b_id++; + + for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) + if ((*iter)->getTuioSourceID()==source_id) free_size++; + + if ((free_size<=maxBlobID[source_id]) && (free_size>0)) { + std::list::iterator closestBlob = freeBlobList.begin(); + + for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) { + if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getDistance(tblb)<(*closestBlob)->getDistance(tblb))) closestBlob = iter; + } + + if (closestBlob!=freeBlobList.end()) { + TuioBlob *freeBlob = (*closestBlob); + b_id = freeBlob->getBlobID(); + freeBlobList.erase(closestBlob); + delete freeBlob; + } + } else maxBlobID[source_id] = b_id; + + frameBlob = new TuioBlob(currentTime,tblb->getSessionID(),b_id,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea()); + if (source_name) frameBlob->setTuioSource(source_id,source_name,source_addr); + blobList.push_back(frameBlob); + + delete tblb; + unlockBlobList(); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioBlob(frameBlob); + + break; + default: + + lockBlobList(); + std::list::iterator iter; + for (iter=blobList.begin(); iter != blobList.end(); iter++) { + if (((*iter)->getTuioSourceID()==source_id) && ((*iter)->getSessionID()==tblb->getSessionID())) { + frameBlob = (*iter); + break; + } + } + + if (iter==blobList.end()) { + unlockBlobList(); + break; + } + + if ( (tblb->getX()!=frameBlob->getX() && tblb->getXSpeed()==0) || (tblb->getY()!=frameBlob->getY() && tblb->getYSpeed()==0) || (tblb->getAngle()!=frameBlob->getAngle() && tblb->getRotationSpeed()==0) ) + frameBlob->update(currentTime,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea()); + else + frameBlob->update(currentTime,tblb->getX(),tblb->getY(),tblb->getAngle(),tblb->getWidth(),tblb->getHeight(),tblb->getArea(),tblb->getXSpeed(),tblb->getYSpeed(),tblb->getRotationSpeed(),tblb->getMotionAccel(),tblb->getRotationAccel()); + + delete tblb; + unlockBlobList(); + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioBlob(frameBlob); + } + } + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->refresh(currentTime); + + } else { + for (std::list::iterator iter=frameBlobs.begin(); iter != frameBlobs.end(); iter++) { + TuioBlob *tblb = (*iter); + delete tblb; + } + } + + frameBlobs.clear(); + } + } + } catch( Exception& e ){ + std::cerr << "error parsing TUIO message: "<< msg.AddressPattern() << " - " << e.what() << std::endl; + } +} + +bool TuioClient::isConnected() { + return receiver->isConnected(); +} + +void TuioClient::connect(bool lock) { + + TuioTime::initSession(); + currentTime.reset(); + + receiver->connect(lock); + + unlockCursorList(); + unlockObjectList(); + unlockBlobList(); +} + +void TuioClient::disconnect() { + + receiver->disconnect(); + + aliveObjectList.clear(); + aliveCursorList.clear(); + aliveBlobList.clear(); + + for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) + delete (*iter); + objectList.clear(); + + for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) + delete (*iter); + cursorList.clear(); + + for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) + delete (*iter); + blobList.clear(); + + for (std::list::iterator iter=freeCursorList.begin(); iter != freeCursorList.end(); iter++) + delete(*iter); + freeCursorList.clear(); + + for (std::list::iterator iter=freeBlobList.begin(); iter != freeBlobList.end(); iter++) + delete(*iter); + freeBlobList.clear(); +} + + +TuioObject* TuioClient::getTuioObject(int src_id, long s_id) { + lockObjectList(); + for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { + if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) { + unlockObjectList(); + return (*iter); + } + } + unlockObjectList(); + return NULL; +} + +TuioCursor* TuioClient::getTuioCursor(int src_id, long s_id) { + lockCursorList(); + for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { + if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) { + unlockCursorList(); + return (*iter); + } + } + unlockCursorList(); + return NULL; +} + +TuioBlob* TuioClient::getTuioBlob(int src_id, long s_id) { + lockBlobList(); + for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { + if (((*iter)->getTuioSourceID()==src_id) && ((*iter)->getSessionID()==s_id)) { + unlockBlobList(); + return (*iter); + } + } + unlockBlobList(); + return NULL; +} + + +std::list TuioClient::getTuioObjects(int source_id) { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { + TuioObject *tobj = (*iter); + if (tobj->getTuioSourceID()==source_id) listBuffer.push_back(tobj); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioClient::getTuioCursors(int source_id) { + lockCursorList(); + std::list listBuffer; + for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { + TuioCursor *tcur = (*iter); + if (tcur->getTuioSourceID()==source_id) listBuffer.push_back(tcur); + } + unlockCursorList(); + return listBuffer; +} + +std::list TuioClient::getTuioBlobs(int source_id) { + lockBlobList(); + std::list listBuffer; + for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { + TuioBlob *tblb = (*iter); + if (tblb->getTuioSourceID()==source_id) listBuffer.push_back(tblb); + } + unlockBlobList(); + return listBuffer; +} + + +std::list TuioClient::copyTuioObjects(int source_id) { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { + TuioObject *tobj = (*iter); + if (tobj->getTuioSourceID()==source_id) listBuffer.push_back(*tobj); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioClient::copyTuioCursors(int source_id) { + lockCursorList(); + std::list listBuffer; + for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { + TuioCursor *tcur = (*iter); + if (tcur->getTuioSourceID()==source_id) listBuffer.push_back(*tcur); + } + unlockCursorList(); + return listBuffer; +} + +std::list TuioClient::copyTuioBlobs(int source_id) { + lockBlobList(); + std::list listBuffer; + for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { + TuioBlob *tblb = (*iter); + if (tblb->getTuioSourceID()==source_id) listBuffer.push_back(*tblb); + } + unlockBlobList(); + return listBuffer; +} + diff --git a/modules/touch/ext/libTUIO/TUIO/TuioClient.h b/modules/touch/ext/libTUIO/TUIO/TuioClient.h new file mode 100644 index 0000000000..7f03ce2580 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioClient.h @@ -0,0 +1,301 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOCLIENT_H +#define INCLUDED_TUIOCLIENT_H + +#include "TuioDispatcher.h" +#include "OscReceiver.h" +#include "oscpack/osc/OscReceivedElements.h" + +#include +#include +#include +#include +#include +#include + +namespace TUIO { + + class OscReceiver; // Forward declaration + + /** + *

The TuioClient class is the central TUIO protocol decoder component. It provides a simple callback infrastructure using the {@link TuioListener} interface. + * In order to receive and decode TUIO messages an instance of TuioClient needs to be created. The TuioClient instance then generates TUIO events + * which are broadcasted to all registered classes that implement the {@link TuioListener} interface.

+ *

+ * TuioClient *client = new TuioClient();
+ * client->addTuioListener(myTuioListener);
+ * client->connect();
+ *

+ * + * @author Martin Kaltenbrunner + * @version 1.1.6 + */ + class LIBDECL TuioClient : public TuioDispatcher { + + public: + /** + * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the default UDP port 3333 + * + */ + TuioClient(); + + /** + * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the provided UDP port + * + * @param port the UDP port the internal UdpReceiver is listening to + */ + TuioClient(int port); + + /** + * This constructor creates a TuioClient that uses the provided OscReceiver for the incoming OSC data + * + * @param oscreceiver the OscReceiver implementation for the chosen transport method (UDP, TCP ...) + */ + TuioClient(OscReceiver *oscreceiver); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioClient(); + + /** + * The TuioClient connects and starts receiving TUIO messages from its associated OscReceiver + * + * @param lock running in the background if set to false (default) + */ + void connect(bool lock=false); + + /** + * The TuioClient disconnects and stops receiving TUIO messages from its associated OscReceiver + */ + void disconnect(); + + /** + * Returns true if this TuioClient is currently connected. + * @return true if this TuioClient is currently connected + */ + bool isConnected(); + + /** + * Returns a List of all currently active TuioObjects + * + * @return a List of TuioObjects + */ + std::list getTuioObjects() { + return TuioDispatcher::getTuioObjects(); + } + + /** + * Returns a List of all currently active TuioObjects + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List of TuioObjects + */ + std::list getTuioObjects(int source_id); + + /** + * Returns a List with a copy of all currently active TuioObjects + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List with a copy of TuioObjects + */ + std::list copyTuioObjects(int source_id); + + + /** + * Returns a List with a copy of all currently active TuioObjects + * + * @return a List with a copy of TuioObjects + */ + std::list copyTuioObjects() { + return TuioDispatcher::copyTuioObjects(); + } + + /** + * Returns the TuioObject corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioObject + * + * @param s_id the session ID of the corresponding TuioObject + * @return an active TuioObject corresponding to the provided Session ID or NULL + */ + TuioObject* getTuioObject(long s_id) { + return getTuioObject(0,s_id); + }; + + /** + * Returns the TuioObject corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioObject + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioObject + * @return an active TuioObject corresponding to the provided Session ID or NULL + */ + TuioObject* getTuioObject(int src_id, long s_id); + + /** + * Returns a List of all currently active TuioCursors + * + * @return a List of TuioCursors + */ + std::list getTuioCursors() { + return TuioDispatcher::getTuioCursors(); + } + + /** + * Returns a List of all currently active TuioCursors + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List of TuioCursors + */ + std::list getTuioCursors(int source_id); + + /** + * Returns a List with a copy of all currently active TuioCursors + * + * @return a List with a copy of TuioCursors + */ + std::list copyTuioCursors() { + return TuioDispatcher::copyTuioCursors(); + } + + /** + * Returns a List with a copy of all currently active TuioCursors + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List with a copy of TuioCursors + */ + std::list copyTuioCursors(int source_id); + + /** + * Returns the TuioCursor corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioCursor + * + * @param s_id the session ID of the corresponding TuioCursor + * @return an active TuioCursor corresponding to the provided Session ID or NULL + */ + TuioCursor* getTuioCursor(long s_id) { + return getTuioCursor(0,s_id); + }; + + /** + * Returns the TuioCursor corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioCursor + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioCursor + * @return an active TuioCursor corresponding to the provided Session ID or NULL + */ + TuioCursor* getTuioCursor(int src_id, long s_id); + + /** + * Returns a List of all currently active TuioBlobs + * + * @return a List of TuioBlobs + */ + std::list getTuioBlobs() { + return TuioDispatcher::getTuioBlobs(); + } + + /** + * Returns a List of all currently active TuioBlobs + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List of TuioBlobs + */ + std::list getTuioBlobs(int source_id); + + /** + * Returns a List with a copy of all currently active TuioBlobs + * + * @return a List with a copy of TuioBlobs + */ + std::list copyTuioBlobs() { + return TuioDispatcher::copyTuioBlobs(); + } + + /** + * Returns a List with a copy of all currently active TuioBlobs + * which are associated to the given Source ID + * + * @param src_id the source ID of the corresponding TUIO source + * @return a List with a copy of TuioBlobs + */ + std::list copyTuioBlobs(int source_id); + + /** + * Returns the TuioBlob corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioBlob + * + * @param s_id the session ID of the corresponding TuioBlob + * @return an active TuioBlob corresponding to the provided Session ID or NULL + */ + TuioBlob* getTuioBlob(long s_id) { + return getTuioBlob(0,s_id); + }; + + /** + * Returns the TuioBlob corresponding to the provided Session ID + * which is associated to the given Source ID + * or NULL if the Session ID does not refer to an active TuioBlob + * + * @param src_id the source ID of the corresponding TUIO source + * @param s_id the session ID of the corresponding TuioBlob + * @return an active TuioBlob corresponding to the provided Session ID or NULL + */ + TuioBlob* getTuioBlob(int src_id, long s_id); + + void processOSC( const osc::ReceivedMessage& message); + + private: + void initialize(); + + std::list frameObjects; + std::list aliveObjectList; + std::list frameCursors; + std::list aliveCursorList; + std::list frameBlobs; + std::list aliveBlobList; + + osc::int32 currentFrame; + TuioTime currentTime; + + std::list freeCursorList, freeCursorBuffer; + std::map maxCursorID; + + std::list freeBlobList, freeBlobBuffer; + std::map maxBlobID; + + std::map sourceList; + int source_id; + char *source_name; + char *source_addr; + + OscReceiver *receiver; + bool local_receiver; + }; +}; +#endif /* INCLUDED_TUIOCLIENT_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioContainer.cpp b/modules/touch/ext/libTUIO/TUIO/TuioContainer.cpp new file mode 100644 index 0000000000..ba85fb6456 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioContainer.cpp @@ -0,0 +1,277 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioContainer.h" +using namespace TUIO; + +TuioContainer::TuioContainer (TuioTime ttime, long si, float xp, float yp):TuioPoint(ttime, xp,yp) +,state(TUIO_ADDED) +,source_id(0) +,source_name("undefined") +,source_addr("localhost") +{ + session_id = si; + x_speed = 0.0f; + y_speed = 0.0f; + motion_speed = 0.0f; + motion_accel = 0.0f; + x_accel = 0.0f; + y_accel = 0.0f; + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + lastPoint = &path.back(); +} + +TuioContainer::TuioContainer (long si, float xp, float yp):TuioPoint(xp,yp) +,state(TUIO_ADDED) +,source_id(0) +,source_name("undefined") +,source_addr("localhost") +{ + session_id = si; + x_speed = 0.0f; + y_speed = 0.0f; + motion_speed = 0.0f; + motion_accel = 0.0f; + x_accel = 0.0f; + y_accel = 0.0f; + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + lastPoint = &path.back(); +} + +TuioContainer::TuioContainer (TuioContainer *tcon):TuioPoint(tcon) +,state(TUIO_ADDED) +,source_id(0) +,source_name("undefined") +,source_addr("localhost") +{ + session_id = tcon->getSessionID(); + x_speed = 0.0f; + y_speed = 0.0f; + motion_speed = 0.0f; + motion_accel = 0.0f; + x_accel = 0.0f; + y_accel = 0.0f; + + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + lastPoint = &path.back(); +} + +void TuioContainer::setTuioSource(int src_id, const char *src_name, const char *src_addr) { + source_id = src_id; + source_name = std::string(src_name); + source_addr = std::string(src_addr); +} + +const char* TuioContainer::getTuioSourceName() const{ + return source_name.c_str(); +} + +const char* TuioContainer::getTuioSourceAddress() const{ + return source_addr.c_str(); +} + +int TuioContainer::getTuioSourceID() const{ + return source_id; +} + +void TuioContainer::update (TuioTime ttime, float xp, float yp) { + lastPoint = &path.back(); + TuioPoint::update(ttime,xp, yp); + + TuioTime diffTime = currentTime - lastPoint->getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + float dx = xpos - lastPoint->getX(); + float dy = ypos - lastPoint->getY(); + float dist = sqrt(dx*dx+dy*dy); + float last_motion_speed = motion_speed; + float last_x_speed = x_speed; + float last_y_speed = y_speed; + + x_speed = dx/dt; + y_speed = dy/dt; + motion_speed = dist/dt; + motion_accel = (motion_speed - last_motion_speed)/dt; + x_accel = (x_speed - last_x_speed)/dt; + y_accel = (y_speed - last_y_speed)/dt; + + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else state = TUIO_STOPPED; +} + +void TuioContainer::stop(TuioTime ttime) { + if ( state==TUIO_IDLE )update(ttime,xpos,ypos); + else state=TUIO_IDLE; +} + +void TuioContainer::update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma) { + TuioPoint::update(ttime,xp, yp); + x_speed = xs; + y_speed = ys; + motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); + motion_accel = ma; + x_accel = ma; + y_accel = ma; + + lastPoint = &path.back(); + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else state = TUIO_STOPPED; +} + +void TuioContainer::update (float xp, float yp, float xs, float ys, float ma) { + TuioPoint::update(xp,yp); + x_speed = xs; + y_speed = ys; + motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); + motion_accel = ma; + x_accel = ma; + y_accel = ma; + + lastPoint = &path.back(); + TuioPoint p(currentTime,xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else state = TUIO_STOPPED; +} + +void TuioContainer::update (TuioContainer *tcon) { + TuioPoint::update(tcon); + x_speed = tcon->getXSpeed(); + y_speed = tcon->getYSpeed(); + motion_speed = tcon->getMotionSpeed(); + motion_accel = tcon->getMotionAccel(); + x_accel = motion_accel; + y_accel = motion_accel; + + lastPoint = &path.back(); + TuioPoint p(tcon->getTuioTime(),xpos,ypos); + path.push_back(p); + if (path.size()>MAX_PATH_SIZE) path.pop_front(); + + if (motion_accel>0) state = TUIO_ACCELERATING; + else if (motion_accel<0) state = TUIO_DECELERATING; + else state = TUIO_STOPPED; +} + +void TuioContainer::remove(TuioTime ttime) { + currentTime = ttime; + state = TUIO_REMOVED; +} + +long TuioContainer::getSessionID() const{ + return session_id; +} + +void TuioContainer::setSessionID(long s_id) { + session_id = s_id; +} + +float TuioContainer::getXSpeed() const{ + return x_speed; +} + +float TuioContainer::getYSpeed() const{ + return y_speed; +} + +TuioPoint TuioContainer::getPosition() const{ + TuioPoint p(xpos,ypos); + return p; +} + +std::list TuioContainer::getPath() const{ + return path; +} + +float TuioContainer::getMotionSpeed() const{ + return motion_speed; +} + +float TuioContainer::getMotionAccel() const{ + return motion_accel; +} + +int TuioContainer::getTuioState() const{ + return state; +} + +bool TuioContainer::isMoving() const{ + if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING)) return true; + else return false; +} + +TuioPoint TuioContainer::predictPosition() { + /*if (path.size()>1) { + std::list::iterator iter = path.end(); + std::advance(iter, -2); + + TuioTime diffTime = currentTime - (*iter).getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + + float tx = x_speed * dt; + float ty = y_speed * dt; + + float nx = xpos+tx-tx*x_accel*dt; + float ny = ypos+ty-ty*y_accel*dt; + + //if (xposFilter && yposFilter) { + // nx = xposFilter->filter(nx,dt); + // ny = yposFilter->filter(ny,dt); + // //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; + //} + + //std::cout << nx << " " << ny << std::endl; + return TuioPoint(nx,ny); + } else return TuioPoint(xpos,ypos);*/ + + TuioTime diffTime = currentTime - lastPoint->getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + + float tx = x_speed * dt; + float ty = y_speed * dt; + + float nx = xpos+tx-tx*x_accel*dt; + float ny = ypos+ty-ty*y_accel*dt; + + //if (xposFilter && yposFilter) { + // nx = xposFilter->filter(nx,dt); + // ny = yposFilter->filter(ny,dt); + // //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; + //} + + //std::cout << nx << " " << ny << std::endl; + return TuioPoint(nx,ny); + + +} + diff --git a/modules/touch/ext/libTUIO/TUIO/TuioContainer.h b/modules/touch/ext/libTUIO/TUIO/TuioContainer.h new file mode 100644 index 0000000000..c25a0b21a8 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioContainer.h @@ -0,0 +1,279 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOCONTAINER_H +#define INCLUDED_TUIOCONTAINER_H + +#include "TuioPoint.h" +#include +#include + +#define TUIO_IDLE 0 +#define TUIO_ADDED 1 +#define TUIO_ACCELERATING 2 +#define TUIO_DECELERATING 3 +#define TUIO_ROTATING 4 +#define TUIO_STOPPED 5 +#define TUIO_REMOVED 6 + +#define MAX_PATH_SIZE 128 + +namespace TUIO { + + /** + * The abstract TuioContainer class defines common attributes that apply to both subclasses {@link TuioObject} and {@link TuioCursor}. + * + * @author Martin Kaltenbrunner + * @version 1.1.6 + */ + class LIBDECL TuioContainer: public TuioPoint { + + + private: + + TuioPoint *lastPoint; + + protected: + /** + * The unique session ID number that is assigned to each TUIO object or cursor. + */ + long session_id; + /** + * The X-axis velocity value. + */ + float x_speed; + /** + * The Y-axis velocity value. + */ + float y_speed; + /** + * The motion speed value. + */ + float motion_speed; + /** + * The motion acceleration value. + */ + float motion_accel; + float x_accel; + float y_accel; + /** + * A List of TuioPoints containing all the previous positions of the TUIO component. + */ + std::list path; + /** + * Reflects the current state of the TuioComponent + */ + int state; + /** + * The ID of the TUIO source + */ + int source_id; + /** + * The name of the TUIO source + */ + std::string source_name; + /** + * The address of the TUIO source + */ + std::string source_addr; + + public: + using TuioPoint::update; + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, X and Y coordinate to the newly created TuioContainer. + * + * @param ttime the TuioTime to assign + * @param si the Session ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + TuioContainer (TuioTime ttime, long si, float xp, float yp); + + /** + * This constructor takes the provided Session ID, X and Y coordinate + * and assigs these values to the newly created TuioContainer. + * + * @param si the Session ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + TuioContainer (long si, float xp, float yp); + + /** + * This constructor takes the atttibutes of the provided TuioContainer + * and assigs these values to the newly created TuioContainer. + * + * @param tcon the TuioContainer to assign + */ + TuioContainer (TuioContainer *tcon); + + /** + * The destructor is doing nothing in particular. + */ + virtual ~TuioContainer(){}; + + /** + * Sets the ID, name and address of the TUIO source + * + * @param src_id the ID of the TUIO source + * @param src_name the name of the TUIO source + * @param src_addr the address of the TUIO source + */ + virtual void setTuioSource(int src_id, const char *src_name, const char *src_addr); + + /** + * Returns the name of the TUIO source + */ + virtual const char* getTuioSourceName() const; + + /** + * Returns the address of the TUIO source + */ + virtual const char* getTuioSourceAddress() const; + + /** + * Returns the ID of the TUIO source + */ + virtual int getTuioSourceID() const; + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate to the private TuioContainer attributes. + * The speed and accleration values are calculated accordingly. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + virtual void update (TuioTime ttime, float xp, float yp); + + /** + * This method is used to calculate the speed and acceleration values of + * TuioContainers with unchanged positions. + */ + virtual void stop(TuioTime ttime); + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate, X and Y velocity and acceleration + * to the private TuioContainer attributes. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param ma the acceleration to assign + */ + virtual void update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma); + + /** + * Assigns the provided X and Y coordinate, X and Y velocity and acceleration + * to the private TuioContainer attributes. The TuioTime time stamp remains unchanged. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param ma the acceleration to assign + */ + virtual void update (float xp, float yp, float xs, float ys, float ma); + + /** + * Takes the atttibutes of the provided TuioContainer + * and assigs these values to this TuioContainer. + * The TuioTime time stamp of this TuioContainer remains unchanged. + * + * @param tcon the TuioContainer to assign + */ + virtual void update (TuioContainer *tcon); + + /** + * Assigns the REMOVE state to this TuioContainer and sets + * its TuioTime time stamp to the provided TuioTime argument. + * + * @param ttime the TuioTime to assign + */ + virtual void remove(TuioTime ttime); + + /** + * Returns the Session ID of this TuioContainer. + * @return the Session ID of this TuioContainer + */ + virtual long getSessionID() const; + + /** + * Sets the Session ID of this TuioContainer. + * @param s_id the new Session ID for this TuioContainer + */ + virtual void setSessionID(long s_id); + + /** + * Returns the X velocity of this TuioContainer. + * @return the X velocity of this TuioContainer + */ + virtual float getXSpeed() const; + + /** + * Returns the Y velocity of this TuioContainer. + * @return the Y velocity of this TuioContainer + */ + virtual float getYSpeed() const; + + /** + * Returns the position of this TuioContainer. + * @return the position of this TuioContainer + */ + virtual TuioPoint getPosition() const; + + /** + * Returns the path of this TuioContainer. + * @return the path of this TuioContainer + */ + virtual std::list getPath() const; + + /** + * Returns the motion speed of this TuioContainer. + * @return the motion speed of this TuioContainer + */ + virtual float getMotionSpeed() const; + + /** + * Returns the motion acceleration of this TuioContainer. + * @return the motion acceleration of this TuioContainer + */ + virtual float getMotionAccel() const; + + /** + * Returns the TUIO state of this TuioContainer. + * @return the TUIO state of this TuioContainer + */ + virtual int getTuioState() const; + + /** + * Returns true of this TuioContainer is moving. + * @return true of this TuioContainer is moving + */ + virtual bool isMoving() const; + + virtual TuioPoint predictPosition(); + }; +} +#endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp b/modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp new file mode 100644 index 0000000000..4df31cd345 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp @@ -0,0 +1,38 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioCursor.h" + +using namespace TUIO; + +TuioCursor::TuioCursor (TuioTime ttime, long si, int ci, float xp, float yp):TuioContainer(ttime,si,xp,yp) { + cursor_id = ci; +} + +TuioCursor::TuioCursor (long si, int ci, float xp, float yp):TuioContainer(si,xp,yp) { + cursor_id = ci; +} + +TuioCursor::TuioCursor (TuioCursor *tcur):TuioContainer(tcur) { + cursor_id = tcur->getCursorID(); +} + +int TuioCursor::getCursorID() const{ + return cursor_id; +}; + diff --git a/modules/touch/ext/libTUIO/TUIO/TuioCursor.h b/modules/touch/ext/libTUIO/TUIO/TuioCursor.h new file mode 100644 index 0000000000..74c0e59d70 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioCursor.h @@ -0,0 +1,86 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOCURSOR_H +#define INCLUDED_TUIOCURSOR_H + +#include "TuioContainer.h" + +namespace TUIO { + + /** + * The TuioCursor class encapsulates /tuio/2Dcur TUIO cursors. + * + * @author Martin Kaltenbrunner + * @version 1.1.6 + */ + class LIBDECL TuioCursor: public TuioContainer { + + protected: + /** + * The individual cursor ID number that is assigned to each TuioCursor. + */ + int cursor_id; + + public: + using TuioContainer::update; + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, Cursor ID, X and Y coordinate to the newly created TuioCursor. + * + * @param ttime the TuioTime to assign + * @param si the Session ID to assign + * @param ci the Cursor ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + TuioCursor (TuioTime ttime, long si, int ci, float xp, float yp); + + /** + * This constructor takes the provided Session ID, Cursor ID, X and Y coordinate + * and assigs these values to the newly created TuioCursor. + * + * @param si the Session ID to assign + * @param ci the Cursor ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + TuioCursor (long si, int ci, float xp, float yp); + + /** + * This constructor takes the atttibutes of the provided TuioCursor + * and assigs these values to the newly created TuioCursor. + * + * @param tcur the TuioCursor to assign + */ + TuioCursor (TuioCursor *tcur); + + /** + * The destructor is doing nothing in particular. + */ + virtual ~TuioCursor(){}; + + /** + * Returns the Cursor ID of this TuioCursor. + * @return the Cursor ID of this TuioCursor + */ + int getCursorID() const; + }; +} +#endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.cpp b/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.cpp new file mode 100644 index 0000000000..c36d59e282 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.cpp @@ -0,0 +1,211 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioDispatcher.h" + +#include +#include +#include +#include + +using namespace TUIO; + +TuioDispatcher::TuioDispatcher() { +#ifndef WIN32 + pthread_mutex_init(&cursorMutex,NULL); + pthread_mutex_init(&objectMutex,NULL); + pthread_mutex_init(&blobMutex,NULL); +#else + cursorMutex = CreateMutex(NULL,FALSE,TEXT("cursorMutex")); + objectMutex = CreateMutex(NULL,FALSE,TEXT("objectMutex")); + blobMutex = CreateMutex(NULL,FALSE,TEXT("blobMutex")); +#endif +} + +TuioDispatcher::~TuioDispatcher() { +#ifndef WIN32 + pthread_mutex_destroy(&cursorMutex); + pthread_mutex_destroy(&objectMutex); + pthread_mutex_destroy(&blobMutex); +#else + CloseHandle(cursorMutex); + CloseHandle(objectMutex); + CloseHandle(blobMutex); +#endif +} + +void TuioDispatcher::lockObjectList() { +#ifndef WIN32 + pthread_mutex_lock(&objectMutex); +#else + WaitForSingleObject(objectMutex, INFINITE); +#endif +} + +void TuioDispatcher::unlockObjectList() { +#ifndef WIN32 + pthread_mutex_unlock(&objectMutex); +#else + ReleaseMutex(objectMutex); +#endif +} + +void TuioDispatcher::lockCursorList() { +#ifndef WIN32 + pthread_mutex_lock(&cursorMutex); +#else + WaitForSingleObject(cursorMutex, INFINITE); +#endif +} + +void TuioDispatcher::unlockCursorList() { +#ifndef WIN32 + pthread_mutex_unlock(&cursorMutex); +#else + ReleaseMutex(cursorMutex); +#endif +} + +void TuioDispatcher::lockBlobList() { +#ifndef WIN32 + pthread_mutex_lock(&blobMutex); +#else + WaitForSingleObject(blobMutex, INFINITE); +#endif +} + +void TuioDispatcher::unlockBlobList() { +#ifndef WIN32 + pthread_mutex_unlock(&blobMutex); +#else + ReleaseMutex(blobMutex); +#endif +} + +void TuioDispatcher::addTuioListener(TuioListener *listener) { + listenerList.push_back(listener); +} + +void TuioDispatcher::removeTuioListener(TuioListener *listener) { + std::list::iterator result = find(listenerList.begin(),listenerList.end(),listener); + if (result!=listenerList.end()) listenerList.remove(listener); +} + +void TuioDispatcher::removeAllTuioListeners() { + listenerList.clear(); +} + +TuioObject* TuioDispatcher::getTuioObject(long s_id) { + lockObjectList(); + for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { + if((*iter)->getSessionID()==s_id) { + unlockObjectList(); + return (*iter); + } + } + unlockObjectList(); + return NULL; +} + +TuioCursor* TuioDispatcher::getTuioCursor(long s_id) { + lockCursorList(); + for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { + if((*iter)->getSessionID()==s_id) { + unlockCursorList(); + return (*iter); + } + } + unlockCursorList(); + return NULL; +} + +TuioBlob* TuioDispatcher::getTuioBlob(long s_id) { + lockBlobList(); + for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { + if((*iter)->getSessionID()==s_id) { + unlockBlobList(); + return (*iter); + } + } + unlockBlobList(); + return NULL; +} + +std::list TuioDispatcher::getTuioObjects() { + lockObjectList(); + std::list listBuffer; + listBuffer.insert(listBuffer.end(), objectList.begin(), objectList.end()); + //std::list listBuffer = objectList; + unlockObjectList(); + return listBuffer; +} + +std::list TuioDispatcher::getTuioCursors() { + lockCursorList(); + std::list listBuffer; + listBuffer.insert(listBuffer.end(), cursorList.begin(), cursorList.end()); + //std::list listBuffer = cursorList; + unlockCursorList(); + return listBuffer; +} + +std::list TuioDispatcher::getTuioBlobs() { + lockBlobList(); + std::list listBuffer; + listBuffer.insert(listBuffer.end(), blobList.begin(), blobList.end()); + //std::list listBuffer = blobList; + unlockBlobList(); + return listBuffer; +} + +std::list TuioDispatcher::copyTuioObjects() { + lockObjectList(); + std::list listBuffer; + for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { + TuioObject *tobj = (*iter); + listBuffer.push_back(*tobj); + } + unlockObjectList(); + return listBuffer; +} + +std::list TuioDispatcher::copyTuioCursors() { + lockCursorList(); + std::list listBuffer; + for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { + TuioCursor *tcur = (*iter); + listBuffer.push_back(*tcur); + } + unlockCursorList(); + + return listBuffer; +} + +std::list TuioDispatcher::copyTuioBlobs() { + lockBlobList(); + std::list listBuffer; + for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { + TuioBlob *tblb = (*iter); + listBuffer.push_back(*tblb); + } + unlockBlobList(); + return listBuffer; +} + + + diff --git a/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.h b/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.h new file mode 100644 index 0000000000..0b8fc79fd2 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.h @@ -0,0 +1,187 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIODISPATCHER_H +#define INCLUDED_TUIODISPATCHER_H + +#include "TuioListener.h" + +#ifndef WIN32 +#include +#else +#include +#endif + +namespace TUIO { + + /** + *

The TuioDispatcher generates TUIO events which are broadcasted to all + * registered classes that implement the {@link TuioListener} interface.

+ * + * @author Martin Kaltenbrunner + * @version 1.1.6 + */ + class LIBDECL TuioDispatcher { + + public: + /** + * This constructor creates a TuioDispatcher + * + */ + TuioDispatcher(); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioDispatcher(); + + /** + * Adds the provided TuioListener to the list of registered TUIO event listeners + * + * @param listener the TuioListener to add + */ + void addTuioListener(TuioListener *listener); + + /** + * Removes the provided TuioListener from the list of registered TUIO event listeners + * + * @param listener the TuioListener to remove + */ + void removeTuioListener(TuioListener *listener); + + /** + * Removes all TuioListener from the list of registered TUIO event listeners + */ + void removeAllTuioListeners(); + + /** + * Returns a List of all currently active TuioObjects + * + * @return a List of all currently active TuioObjects + */ + std::list getTuioObjects(); + + /** + * Returns a List with a copy of currently active TuioObjects + * + * @return a List with a copy of all currently active TuioObjects + */ + std::list copyTuioObjects(); + + /** + * Returns a List of all currently active TuioCursors + * + * @return a List of all currently active TuioCursors + */ + std::list getTuioCursors(); + + /** + * Returns a List with a copy of currently active TuioCursors + * + * @return a List with a copy of all currently active TuioCursors + */ + std::list copyTuioCursors(); + + /** + * Returns a List of all currently active TuioBlobs + * + * @return a List of all currently active TuioBlobs + */ + std::list getTuioBlobs(); + + /** + * Returns a List with a copy of currently active TuioBlobs + * + * @return a List with a copy of all currently active TuioBlobs + */ + std::list copyTuioBlobs(); + + /** + * Returns the TuioObject corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioObject + * + * @return an active TuioObject corresponding to the provided Session ID or NULL + */ + TuioObject* getTuioObject(long s_id); + + /** + * Returns the TuioCursor corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioCursor + * + * @return an active TuioCursor corresponding to the provided Session ID or NULL + */ + TuioCursor* getTuioCursor(long s_id); + + /** + * Returns the TuioBlob corresponding to the provided Session ID + * or NULL if the Session ID does not refer to an active TuioBlob + * + * @return an active TuioBlob corresponding to the provided Session ID or NULL + */ + TuioBlob* getTuioBlob(long s_id); + + /** + * Locks the TuioObject list in order to avoid updates during access + */ + void lockObjectList(); + + /** + * Releases the lock of the TuioObject list + */ + void unlockObjectList(); + + /** + * Locks the TuioCursor list in order to avoid updates during access + */ + void lockCursorList(); + + /** + * Releases the lock of the TuioCursor list + */ + void unlockCursorList(); + + /** + * Locks the TuioBlob list in order to avoid updates during access + */ + void lockBlobList(); + + /** + * Releases the lock of the TuioBlob list + */ + void unlockBlobList(); + + protected: + std::list listenerList; + + std::list objectList; + std::list cursorList; + std::list blobList; + +#ifndef WIN32 + pthread_mutex_t objectMutex; + pthread_mutex_t cursorMutex; + pthread_mutex_t blobMutex; +#else + HANDLE objectMutex; + HANDLE cursorMutex; + HANDLE blobMutex; +#endif + + }; +} +#endif /* INCLUDED_TUIODISPATCHER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioListener.h b/modules/touch/ext/libTUIO/TUIO/TuioListener.h new file mode 100644 index 0000000000..099f8805dd --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioListener.h @@ -0,0 +1,124 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOLISTENER_H +#define INCLUDED_TUIOLISTENER_H + +#include "TuioObject.h" +#include "TuioCursor.h" +#include "TuioBlob.h" + +namespace TUIO { + + /** + *

The TuioListener interface provides a simple callback infrastructure which is used by the {@link TuioClient} class + * to dispatch TUIO events to all registered instances of classes that implement the TuioListener interface defined here.

+ *

Any class that implements the TuioListener interface is required to implement all of the callback methods defined here. + * The {@link TuioClient} makes use of these interface methods in order to dispatch TUIO events to all registered TuioListener implementations.

+ *

+ * public class MyTuioListener implements TuioListener
+ * ...

+ * MyTuioListener listener = new MyTuioListener();
+ * TuioClient client = new TuioClient();
+ * client.addTuioListener(listener);
+ * client.start();
+ *

+ * + * @author Martin Kaltenbrunner + * @version 1.1.6 + */ + class LIBDECL TuioListener { + + public: + /** + * The destructor is doing nothing in particular. + */ + virtual ~TuioListener(){}; + + /** + * This callback method is invoked by the TuioClient when a new TuioObject is added to the session. + * + * @param tobj the TuioObject reference associated to the addTuioObject event + */ + virtual void addTuioObject(TuioObject *tobj)=0; + + /** + * This callback method is invoked by the TuioClient when an existing TuioObject is updated during the session. + * + * @param tobj the TuioObject reference associated to the updateTuioObject event + */ + virtual void updateTuioObject(TuioObject *tobj)=0; + + /** + * This callback method is invoked by the TuioClient when an existing TuioObject is removed from the session. + * + * @param tobj the TuioObject reference associated to the removeTuioObject event + */ + virtual void removeTuioObject(TuioObject *tobj)=0; + + /** + * This callback method is invoked by the TuioClient when a new TuioCursor is added to the session. + * + * @param tcur the TuioCursor reference associated to the addTuioCursor event + */ + virtual void addTuioCursor(TuioCursor *tcur)=0; + + /** + * This callback method is invoked by the TuioClient when an existing TuioCursor is updated during the session. + * + * @param tcur the TuioCursor reference associated to the updateTuioCursor event + */ + virtual void updateTuioCursor(TuioCursor *tcur)=0; + + /** + * This callback method is invoked by the TuioClient when an existing TuioCursor is removed from the session. + * + * @param tcur the TuioCursor reference associated to the removeTuioCursor event + */ + virtual void removeTuioCursor(TuioCursor *tcur)=0; + + /** + * This callback method is invoked by the TuioClient when a new TuioBlob is added to the session. + * + * @param tcur the TuioBlob reference associated to the addTuioBlob event + */ + virtual void addTuioBlob(TuioBlob *tblb)=0; + + /** + * This callback method is invoked by the TuioClient when an existing TuioBlob is updated during the session. + * + * @param tblb the TuioBlob reference associated to the updateTuioBlob event + */ + virtual void updateTuioBlob(TuioBlob *tblb)=0; + + /** + * This callback method is invoked by the TuioClient when an existing TuioBlob is removed from the session. + * + * @param tblb the TuioBlob reference associated to the removeTuioBlob event + */ + virtual void removeTuioBlob(TuioBlob *tblb)=0; + + /** + * This callback method is invoked by the TuioClient to mark the end of a received TUIO message bundle. + * + * @param ftime the TuioTime associated to the current TUIO message bundle + */ + virtual void refresh(TuioTime ftime)=0; + }; +} +#endif /* INCLUDED_TUIOLISTENER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioManager.cpp b/modules/touch/ext/libTUIO/TUIO/TuioManager.cpp new file mode 100644 index 0000000000..db16a61d0f --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioManager.cpp @@ -0,0 +1,615 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioManager.h" +using namespace TUIO; + + +TuioManager::TuioManager() + : currentFrameTime(TuioTime::getSystemTime()) + , currentFrame(-1) + , maxCursorID(-1) + , maxBlobID(-1) + , sessionID(-1) + , updateObject(false) + , updateCursor(false) + , updateBlob(false) + , verbose(false) + , invert_x(false) + , invert_y(false) + , invert_a(false) +{ + +} + +TuioManager::~TuioManager() { +} + + +TuioObject* TuioManager::addTuioObject(int f_id, float x, float y, float a) { + sessionID++; + TuioObject *tobj = new TuioObject(currentFrameTime, sessionID, f_id, x, y, a); + objectList.push_back(tobj); + updateObject = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioObject(tobj); + + if (verbose) + std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; + + return tobj; +} + +void TuioManager::addExternalTuioObject(TuioObject *tobj) { + if (tobj==NULL) return; + tobj->setSessionID(sessionID++); + objectList.push_back(tobj); + updateObject = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioObject(tobj); + + if (verbose) + std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; +} + +void TuioManager::updateTuioObject(TuioObject *tobj, float x, float y, float a) { + if (tobj==NULL) return; + if (tobj->getTuioTime()==currentFrameTime) return; + tobj->update(currentFrameTime,x,y,a); + updateObject = true; + + if (tobj->isMoving()) { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioObject(tobj); + + if (verbose) + std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() + << " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; + } +} + +void TuioManager::updateExternalTuioObject(TuioObject *tobj) { + if (tobj==NULL) return; + updateObject = true; + + if (tobj->isMoving()) { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioObject(tobj); + + if (verbose) + std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() + << " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; + } +} + +void TuioManager::removeTuioObject(TuioObject *tobj) { + if (tobj==NULL) return; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioObject(tobj); + + if (verbose) + std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ")" << std::endl; + + objectList.remove(tobj); + delete tobj; + updateObject = true; +} + +void TuioManager::removeExternalTuioObject(TuioObject *tobj) { + if (tobj==NULL) return; + objectList.remove(tobj); + updateObject = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioObject(tobj); + + if (verbose) + std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ")" << std::endl; +} + +TuioCursor* TuioManager::addTuioCursor(float x, float y) { + sessionID++; + + int cursorID = (int)cursorList.size(); + if ((int)(cursorList.size())<=maxCursorID) { + std::list::iterator closestCursor = freeCursorList.begin(); + + for(std::list::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) { + if((*iter)->getDistance(x,y)<(*closestCursor)->getDistance(x,y)) closestCursor = iter; + } + + TuioCursor *freeCursor = (*closestCursor); + cursorID = (*closestCursor)->getCursorID(); + freeCursorList.erase(closestCursor); + delete freeCursor; + } else maxCursorID = cursorID; + + TuioCursor *tcur = new TuioCursor(currentFrameTime, sessionID, cursorID, x, y); + cursorList.push_back(tcur); + updateCursor = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioCursor(tcur); + + if (verbose) + std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl; + + return tcur; +} + +void TuioManager::addExternalTuioCursor(TuioCursor *tcur) { + if (tcur==NULL) return; + tcur->setSessionID(sessionID++); + cursorList.push_back(tcur); + updateCursor = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioCursor(tcur); + + if (verbose) + std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl; +} + +void TuioManager::updateTuioCursor(TuioCursor *tcur,float x, float y) { + if (tcur==NULL) return; + //if (tcur->getTuioTime()==currentFrameTime) return; + tcur->update(currentFrameTime,x,y); + updateCursor = true; + + if (tcur->isMoving()) { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioCursor(tcur); + + if (verbose) + std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() + << " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl; + } +} + +void TuioManager::updateExternalTuioCursor(TuioCursor *tcur) { + if (tcur==NULL) return; + updateCursor = true; + + if (tcur->isMoving()) { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioCursor(tcur); + + if (verbose) + std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() + << " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl; + } +} + +void TuioManager::removeTuioCursor(TuioCursor *tcur) { + if (tcur==NULL) return; + + cursorList.remove(tcur); + tcur->remove(currentFrameTime); + updateCursor = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioCursor(tcur); + + if (verbose) + std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ")" << std::endl; + + if (tcur->getCursorID()==maxCursorID) { + maxCursorID = -1; + delete tcur; + + if (cursorList.size()>0) { + std::list::iterator clist; + for (clist=cursorList.begin(); clist != cursorList.end(); clist++) { + int cursorID = (*clist)->getCursorID(); + if (cursorID>maxCursorID) maxCursorID=cursorID; + } + + freeCursorBuffer.clear(); + for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { + TuioCursor *freeCursor = (*flist); + if (freeCursor->getCursorID()>maxCursorID) delete freeCursor; + else freeCursorBuffer.push_back(freeCursor); + } + + freeCursorList = freeCursorBuffer; + + } else { + for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { + TuioCursor *freeCursor = (*flist); + delete freeCursor; + } + freeCursorList.clear(); + } + } else if (tcur->getCursorID()::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioCursor(tcur); + + if (verbose) + std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ")" << std::endl; +} + +TuioBlob* TuioManager::addTuioBlob(float x, float y, float a, float w, float h, float f) { + sessionID++; + + int blobID = (int)blobList.size(); + if ((int)(blobList.size())<=maxBlobID) { + std::list::iterator closestBlob = freeBlobList.begin(); + + for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) { + if((*iter)->getDistance(x,y)<(*closestBlob)->getDistance(x,y)) closestBlob = iter; + } + + TuioBlob *freeBlob = (*closestBlob); + blobID = (*closestBlob)->getBlobID(); + freeBlobList.erase(closestBlob); + delete freeBlob; + } else maxBlobID = blobID; + + TuioBlob *tblb = new TuioBlob(currentFrameTime, sessionID, blobID, x, y, a, w, h, f); + blobList.push_back(tblb); + updateBlob = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioBlob(tblb); + + if (verbose) + std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; + + return tblb; +} + +void TuioManager::addExternalTuioBlob(TuioBlob *tblb) { + if (tblb==NULL) return; + + int blobID = (int)blobList.size(); + if (blobID <= maxBlobID) { + std::list::iterator closestBlob = freeBlobList.begin(); + + for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) { + if((*iter)->getDistance(tblb->getX(),tblb->getY())<(*closestBlob)->getDistance(tblb->getX(),tblb->getY())) closestBlob = iter; + } + + TuioBlob *freeBlob = (*closestBlob); + blobID = (*closestBlob)->getBlobID(); + freeBlobList.erase(closestBlob); + delete freeBlob; + } else maxBlobID = blobID; + + tblb->setSessionID(sessionID++); + tblb->setBlobID(blobID); + + blobList.push_back(tblb); + updateBlob = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->addTuioBlob(tblb); + + if (verbose) + std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; +} + +void TuioManager::updateTuioBlob(TuioBlob *tblb,float x, float y, float a, float w, float h, float f) { + if (tblb==NULL) return; + if (tblb->getTuioTime()==currentFrameTime) return; + tblb->update(currentFrameTime,x,y,a,w,h,f); + updateBlob = true; + + if (tblb->isMoving()) { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioBlob(tblb); + + if (verbose) + std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() + << " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl; + } +} + +void TuioManager::updateExternalTuioBlob(TuioBlob *tblb) { + if (tblb==NULL) return; + updateBlob = true; + + if (tblb->isMoving()) { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->updateTuioBlob(tblb); + + if (verbose) + std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() + << " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl; + } +} + +void TuioManager::removeTuioBlob(TuioBlob *tblb) { + if (tblb==NULL) return; + + blobList.remove(tblb); + tblb->remove(currentFrameTime); + updateBlob = true; + + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioBlob(tblb); + + if (verbose) + std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ")" << std::endl; + + if (tblb->getBlobID()==maxBlobID) { + maxBlobID = -1; + delete tblb; + + if (blobList.size()>0) { + std::list::iterator clist; + for (clist=blobList.begin(); clist != blobList.end(); clist++) { + int blobID = (*clist)->getBlobID(); + if (blobID>maxBlobID) maxBlobID=blobID; + } + + freeBlobBuffer.clear(); + for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { + TuioBlob *freeBlob = (*flist); + if (freeBlob->getBlobID()>maxBlobID) delete freeBlob; + else freeBlobBuffer.push_back(freeBlob); + } + + freeBlobList = freeBlobBuffer; + + } else { + for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { + TuioBlob *freeBlob = (*flist); + delete freeBlob; + } + freeBlobList.clear(); + } + } else if (tblb->getBlobID()::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->removeTuioBlob(tblb); + + if (verbose) + std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ")" << std::endl; +} + +long TuioManager::getSessionID() { + sessionID++; + return sessionID; +} + +long TuioManager::getFrameID() { + return currentFrame; +} + +TuioTime TuioManager::getFrameTime() { + return currentFrameTime; +} + +void TuioManager::initFrame(TuioTime ttime) { + currentFrameTime = TuioTime(ttime); + currentFrame++; +} + +void TuioManager::commitFrame() { + for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) + (*listener)->refresh(currentFrameTime); +} + +TuioObject* TuioManager::getClosestTuioObject(float xp, float yp) { + + TuioObject *closestObject = NULL; + float closestDistance = 1.0f; + + for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { + float distance = (*iter)->getDistance(xp,yp); + if(distance::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { + float distance = (*iter)->getDistance(xp,yp); + if(distance::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { + float distance = (*iter)->getDistance(xp,yp); + if(distance TuioManager::getUntouchedObjects() { + + std::list untouched; + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { + TuioObject *tobj = (*tuioObject); + if (tobj->getTuioTime()!=currentFrameTime) untouched.push_back(tobj); + } + return untouched; +} + +void TuioManager::stopUntouchedMovingObjects() { + + std::list untouched; + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { + + TuioObject *tobj = (*tuioObject); + if ((tobj->getTuioTime()!=currentFrameTime) && (tobj->isMoving())) { + tobj->stop(currentFrameTime); + updateObject = true; + if (verbose) + std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() + << " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; + } + } +} + +void TuioManager::removeUntouchedStoppedObjects() { + + std::list::iterator tuioObject = objectList.begin(); + while (tuioObject!=objectList.end()) { + TuioObject *tobj = (*tuioObject); + if ((tobj->getTuioTime()!=currentFrameTime) && (!tobj->isMoving())) { + removeTuioObject(tobj); + tuioObject = objectList.begin(); + } else tuioObject++; + } +} + +void TuioManager::resetTuioObjects() { + + std::list::iterator tuioObject = objectList.begin(); + while (tuioObject!=objectList.end()) { + removeTuioObject((*tuioObject)); + tuioObject = objectList.begin(); + } +} + +std::list TuioManager::getUntouchedCursors() { + + std::list untouched; + for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { + TuioCursor *tcur = (*tuioCursor); + if (tcur->getTuioTime()!=currentFrameTime) untouched.push_back(tcur); + } + return untouched; +} + +void TuioManager::stopUntouchedMovingCursors() { + + std::list untouched; + for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { + TuioCursor *tcur = (*tuioCursor); + if ((tcur->getTuioTime()!=currentFrameTime) && (tcur->isMoving())) { + tcur->stop(currentFrameTime); + updateCursor = true; + if (verbose) + std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() + << " " << tcur->getXSpeed() << " " << tcur->getYSpeed()<< " " << tcur->getMotionAccel() << " " << std::endl; + } + } +} + +void TuioManager::removeUntouchedStoppedCursors() { + + if (cursorList.size()==0) return; + std::list::iterator tuioCursor = cursorList.begin(); + while (tuioCursor!=cursorList.end()) { + TuioCursor *tcur = (*tuioCursor); + if ((tcur->getTuioTime()!=currentFrameTime) && (!tcur->isMoving())) { + removeTuioCursor(tcur); + tuioCursor = cursorList.begin(); + } else tuioCursor++; + } +} + +void TuioManager::resetTuioCursors() { + + std::list::iterator tuioCursor = cursorList.begin(); + while (tuioCursor!=cursorList.end()) { + removeTuioCursor((*tuioCursor)); + tuioCursor = cursorList.begin(); + } +} + +std::list TuioManager::getUntouchedBlobs() { + + std::list untouched; + for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { + TuioBlob *tblb = (*tuioBlob); + if (tblb->getTuioTime()!=currentFrameTime) untouched.push_back(tblb); + } + return untouched; +} + +void TuioManager::stopUntouchedMovingBlobs() { + + std::list untouched; + for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { + TuioBlob *tblb = (*tuioBlob); + if ((tblb->getTuioTime()!=currentFrameTime) && (tblb->isMoving())) { + tblb->stop(currentFrameTime); + updateBlob = true; + if (verbose) + std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() + << " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl; + } + } +} + +void TuioManager::removeUntouchedStoppedBlobs() { + + std::list::iterator tuioBlob = blobList.begin(); + while (tuioBlob!=blobList.end()) { + TuioBlob *tblb = (*tuioBlob); + if ((tblb->getTuioTime()!=currentFrameTime) && (!tblb->isMoving())) { + removeTuioBlob(tblb); + tuioBlob = blobList.begin(); + } else tuioBlob++; + } +} + +void TuioManager::resetTuioBlobs() { + + std::list::iterator tuioBlob = blobList.begin(); + while (tuioBlob!=blobList.end()) { + removeTuioBlob((*tuioBlob)); + tuioBlob = blobList.begin(); + } +} diff --git a/modules/touch/ext/libTUIO/TUIO/TuioManager.h b/modules/touch/ext/libTUIO/TUIO/TuioManager.h new file mode 100644 index 0000000000..3eabbde47b --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioManager.h @@ -0,0 +1,389 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOMANAGER_H +#define INCLUDED_TUIOMANAGER_H + +#include "TuioDispatcher.h" + +#include +#include +#include + +#define OBJ_MESSAGE_SIZE 108 // setMessage + fseqMessage size +#define CUR_MESSAGE_SIZE 88 +#define BLB_MESSAGE_SIZE 116 + +namespace TUIO { + /** + *

The TuioManager class is the central TUIO session management component.

+ *

During runtime the each frame is marked with the initFrame and commitFrame methods, + * while the currently present TuioObjects are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

+ *

+ * TuioManager *manager = new TuioManager();
+ * ...
+ * server->initFrame(TuioTime::getSessionTime());
+ * TuioObject *tobj = server->addTuioObject(xpos,ypos, angle);
+ * TuioCursor *tcur = server->addTuioObject(xpos,ypos);
+ * TuioBlob *tblb = server->addTuioBlob(xpos,ypos,width,height,angle);
+ * server->commitFrame();
+ * ...
+ * server->initFrame(TuioTime::getSessionTime());
+ * server->updateTuioObject(tobj, xpos,ypos, angle);
+ * server->updateTuioCursor(tcur, xpos,ypos);
+ * server->updateTuioBlob(tblb, xpos,ypos,width,height,angle);
+ * server->commitFrame();
+ * ...
+ * server->initFrame(TuioTime::getSessionTime());
+ * server->removeTuioObject(tobj);
+ * server->removeTuioCursor(tcur);
+ * server->removeTuioBlob(tblb);
+ * server->commitFrame();
+ *

+ * + * @author Martin Kaltenbrunner + * @version 1.1.6 + */ + class LIBDECL TuioManager : public TuioDispatcher { + + public: + + /** + * The default constructor creates a TuioManager + */ + TuioManager(); + + /** + * The destructor is doing nothing in particular. + */ + ~TuioManager(); + + /** + * Creates a new TuioObject based on the given arguments. + * The new TuioObject is added to the TuioServer's internal list of active TuioObjects + * and a reference is returned to the caller. + * + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + * @return reference to the created TuioObject + */ + TuioObject* addTuioObject(int sym, float xp, float yp, float a); + + /** + * Updates the referenced TuioObject based on the given arguments. + * + * @param tobj the TuioObject to update + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + void updateTuioObject(TuioObject *tobj, float xp, float yp, float a); + + /** + * Removes the referenced TuioObject from the TuioServer's internal list of TuioObjects + * and deletes the referenced TuioObject afterwards + * + * @param tobj the TuioObject to remove + */ + void removeTuioObject(TuioObject *tobj); + + /** + * Adds an externally managed TuioObject to the TuioServer's internal list of active TuioObjects + * + * @param tobj the TuioObject to add + */ + void addExternalTuioObject(TuioObject *tobj); + + /** + * Updates an externally managed TuioObject + * + * @param tobj the TuioObject to update + */ + void updateExternalTuioObject(TuioObject *tobj); + + /** + * Removes an externally managed TuioObject from the TuioServer's internal list of TuioObjects + * The referenced TuioObject is not deleted + * + * @param tobj the TuioObject to remove + */ + void removeExternalTuioObject(TuioObject *tobj); + + /** + * Creates a new TuioCursor based on the given arguments. + * The new TuioCursor is added to the TuioServer's internal list of active TuioCursors + * and a reference is returned to the caller. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @return reference to the created TuioCursor + */ + TuioCursor* addTuioCursor(float xp, float yp); + + /** + * Updates the referenced TuioCursor based on the given arguments. + * + * @param tcur the TuioObject to update + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + */ + void updateTuioCursor(TuioCursor *tcur, float xp, float yp); + + /** + * Removes the referenced TuioCursor from the TuioServer's internal list of TuioCursors + * and deletes the referenced TuioCursor afterwards + * + * @param tcur the TuioCursor to remove + */ + void removeTuioCursor(TuioCursor *tcur); + + /** + * Adds an externally managed TuioCursor + * + * @param tcur the TuioCursor to add + */ + void addExternalTuioCursor(TuioCursor *tcur); + + /** + * Updates an externally managed TuioCursor + * + * @param tcur the TuioCursor to update + */ + void updateExternalTuioCursor(TuioCursor *tcur); + + /** + * Removes an externally managed TuioCursor from the TuioServer's internal list of TuioCursor + * The referenced TuioCursor is not deleted + * + * @param tcur the TuioCursor to remove + */ + void removeExternalTuioCursor(TuioCursor *tcur); + + /** + * Creates a new TuioBlob based on the given arguments. + * The new TuioBlob is added to the TuioServer's internal list of active TuioBlobs + * and a reference is returned to the caller. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param angle the angle to assign + * @param width the width to assign + * @param height the height to assign + * @param area the area to assign + * @return reference to the created TuioBlob + */ + TuioBlob* addTuioBlob(float xp, float yp, float angle, float width, float height, float area); + + /** + * Updates the referenced TuioBlob based on the given arguments. + * + * @param tblb the TuioObject to update + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param angle the angle to assign + * @param width the width to assign + * @param height the height to assign + * @param area the area to assign + */ + void updateTuioBlob(TuioBlob *tblb, float xp, float yp, float angle, float width, float height, float area); + + /** + * Removes the referenced TuioBlob from the TuioServer's internal list of TuioBlobs + * and deletes the referenced TuioBlob afterwards + * + * @param tblb the TuioBlob to remove + */ + void removeTuioBlob(TuioBlob *tblb); + + /** + * Updates an externally managed TuioBlob + * + * @param tblb the TuioBlob to update + */ + void addExternalTuioBlob(TuioBlob *tblb); + + /** + * Updates an externally managed TuioBlob + * + * @param tblb the TuioBlob to update + */ + void updateExternalTuioBlob(TuioBlob *tblb); + + /** + * Removes an externally managed TuioBlob from the TuioServer's internal list of TuioBlob + * The referenced TuioBlob is not deleted + * + * @param tblb the TuioBlob to remove + */ + void removeExternalTuioBlob(TuioBlob *tblb); + + /** + * Initializes a new frame with the given TuioTime + * + * @param ttime the frame time + */ + void initFrame(TuioTime ttime); + + /** + * Commits the current frame. + * Generates and sends TUIO messages of all currently active and updated TuioObjects and TuioCursors. + */ + void commitFrame(); + + /** + * Returns the next available Session ID for external use. + * @return the next available Session ID for external use + */ + long getSessionID(); + + /** + * Returns the current frame ID for external use. + * @return the current frame ID for external use + */ + long getFrameID(); + + /** + * Returns the current frame ID for external use. + * @return the current frame ID for external use + */ + TuioTime getFrameTime(); + + /** + * Returns a List of all currently inactive TuioObjects + * + * @return a List of all currently inactive TuioObjects + */ + std::list getUntouchedObjects(); + + /** + * Returns a List of all currently inactive TuioCursors + * + * @return a List of all currently inactive TuioCursors + */ + std::list getUntouchedCursors(); + + /** + * Returns a List of all currently inactive TuioBlobs + * + * @return a List of all currently inactive TuioBlobs + */ + std::list getUntouchedBlobs(); + + /** + * Calculates speed and acceleration values for all currently inactive TuioObjects + */ + void stopUntouchedMovingObjects(); + + /** + * Calculates speed and acceleration values for all currently inactive TuioCursors + */ + void stopUntouchedMovingCursors(); + + /** + * Calculates speed and acceleration values for all currently inactive TuioBlobs + */ + void stopUntouchedMovingBlobs(); + + /** + * Removes all currently inactive TuioObjects from the TuioServer's internal list of TuioObjects + */ + void removeUntouchedStoppedObjects(); + + /** + * Removes all currently inactive TuioCursors from the TuioServer's internal list of TuioCursors + */ + void removeUntouchedStoppedCursors(); + + /** + * Removes all currently inactive TuioCursors from the TuioServer's internal list of TuioBlobs + */ + void removeUntouchedStoppedBlobs(); + + /** + * Returns the TuioObject closest to the provided coordinates + * or NULL if there isn't any active TuioObject + * + * @return the closest TuioObject to the provided coordinates or NULL + */ + TuioObject* getClosestTuioObject(float xp, float yp); + + /** + * Returns the TuioCursor closest to the provided coordinates + * or NULL if there isn't any active TuioCursor + * + * @return the closest TuioCursor corresponding to the provided coordinates or NULL + */ + TuioCursor* getClosestTuioCursor(float xp, float yp); + + /** + * Returns the TuioBlob closest to the provided coordinates + * or NULL if there isn't any active TuioBlob + * + * @return the closest TuioBlob corresponding to the provided coordinates or NULL + */ + TuioBlob* getClosestTuioBlob(float xp, float yp); + + /** + * The TuioServer prints verbose TUIO event messages to the console if set to true. + * @param verbose print verbose messages if set to true + */ + void setVerbose(bool verbose) { this->verbose=verbose; } + bool isVerbose() { return verbose; } + + void setInversion(bool ix, bool iy, bool ia) { + invert_x = ix; + invert_y = iy; + invert_a = ia; + }; + + void setInvertXpos(bool ix) { invert_x = ix; }; + void setInvertYpos(bool iy) { invert_y = iy; }; + void setInvertAngle(bool ia) { invert_a = ia; }; + bool getInvertXpos() { return invert_x; }; + bool getInvertYpos() { return invert_y; }; + bool getInvertAngle() { return invert_a; }; + void resetTuioObjects(); + void resetTuioCursors(); + void resetTuioBlobs(); + + protected: + std::list freeCursorList; + std::list freeCursorBuffer; + + std::list freeBlobList; + std::list freeBlobBuffer; + + TuioTime currentFrameTime; + long currentFrame; + int maxCursorID; + int maxBlobID; + long sessionID; + + bool updateObject; + bool updateCursor; + bool updateBlob; + bool verbose; + + bool invert_x; + bool invert_y; + bool invert_a; + }; +} +#endif /* INCLUDED_TUIOMANAGER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioObject.cpp b/modules/touch/ext/libTUIO/TUIO/TuioObject.cpp new file mode 100644 index 0000000000..9c818ca37c --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioObject.cpp @@ -0,0 +1,165 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioObject.h" + +using namespace TUIO; + +TuioObject::TuioObject (TuioTime ttime, long si, int sym, float xp, float yp, float a):TuioContainer(ttime, si, xp, yp) { + symbol_id = sym; + angle = a; + angle_sum = a; + rotation_speed = 0.0f; + rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; +} + +TuioObject::TuioObject (long si, int sym, float xp, float yp, float a):TuioContainer(si, xp, yp) { + symbol_id = sym; + angle = a; + angle_sum = a; + rotation_speed = 0.0f; + rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; +} + +TuioObject::TuioObject (TuioObject *tobj):TuioContainer(tobj) { + symbol_id = tobj->getSymbolID(); + angle = tobj->getAngle(); + angle_sum = tobj->getAngleSum(); + rotation_speed = 0.0f; + rotation_accel = 0.0f; + + angleFilter = NULL; + angleThreshold = 0.0f; +} + +void TuioObject::update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { + TuioContainer::update(ttime,xp,yp,xs,ys,ma); + angle = a; + angle_sum = a; + rotation_speed = rs; + rotation_accel = ra; + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + + +void TuioObject::update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { + TuioContainer::update(xp,yp,xs,ys,ma); + angle = a; + angle_sum = a; + rotation_speed = rs; + rotation_accel = ra; + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + +void TuioObject::update (TuioTime ttime, float xp, float yp, float a) { + TuioPoint lastPoint = path.back(); + TuioContainer::update(ttime,xp,yp); + + TuioTime diffTime = currentTime - lastPoint.getTuioTime(); + float dt = diffTime.getTotalMilliseconds()/1000.0f; + float last_rotation_speed = rotation_speed; + + float prev_angle = angle_sum; + float da = a-angle; + if (da > M_PI/2.0f) angle_sum += (da-2*M_PI); + else if (da < M_PI/-2.0f) angle_sum += (da+2*M_PI); + else angle_sum += da; + + if (angleFilter) angle_sum = angleFilter->filter(angle_sum,dt); + if (fabs(angle_sum-prev_angle) 0.75f) da-=1.0f; + else if (da < -0.75f) da+=1.0f; + + rotation_speed = (float)da/dt; + rotation_accel = (rotation_speed - last_rotation_speed)/dt; + + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + +void TuioObject::stop (TuioTime ttime) { + update(ttime,xpos,ypos,angle); +} + +void TuioObject::update (TuioObject *tobj) { + TuioContainer::update(tobj); + angle = tobj->getAngle(); + angle_sum = tobj->getAngleSum(); + rotation_speed = tobj->getRotationSpeed(); + rotation_accel = tobj->getRotationAccel(); + if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; +} + +int TuioObject::getSymbolID() const{ + return symbol_id; +} + +float TuioObject::getAngle() const{ + return angle; +} + +float TuioObject::getAngleSum() const{ + return angle_sum; +} + +float TuioObject::getAngleDegrees() const{ + return (float)(angle/M_PI*180); +} + +float TuioObject::getRotationSpeed() const{ + return rotation_speed; +} + +float TuioObject::getRotationAccel() const{ + return rotation_accel; +} + +bool TuioObject::isMoving() const{ + if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true; + else return false; +} + +void TuioObject::addAngleThreshold(float thresh) { + angleThreshold = thresh; +} + +void TuioObject::removeAngleThreshold() { + angleThreshold = 0.0f; +} + +void TuioObject::addAngleFilter(float mcut, float beta) { + + if (angleFilter) delete angleFilter; + angleFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioObject::removeAngleFilter() { + + if (angleFilter) delete angleFilter; + angleFilter = NULL; +} diff --git a/modules/touch/ext/libTUIO/TUIO/TuioObject.h b/modules/touch/ext/libTUIO/TUIO/TuioObject.h new file mode 100644 index 0000000000..b027c79fe3 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioObject.h @@ -0,0 +1,213 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#ifndef INCLUDED_TUIOOBJECT_H +#define INCLUDED_TUIOOBJECT_H + +#include "TuioContainer.h" + +namespace TUIO { + + /** + * The TuioObject class encapsulates /tuio/2Dobj TUIO objects. + * + * @author Martin Kaltenbrunner + * @version 1.1.6 + */ + class LIBDECL TuioObject: public TuioContainer { + + protected: + /** + * The individual symbol ID number that is assigned to each TuioObject. + */ + int symbol_id; + /** + * The rotation angle value. + */ + float angle; + /** + * The accumulated angle value. + */ + float angle_sum; + /** + * The rotation speed value. + */ + float rotation_speed; + /** + * The rotation acceleration value. + */ + float rotation_accel; + + float angleThreshold; + OneEuroFilter *angleFilter; + + public: + using TuioContainer::update; + + /** + * This constructor takes a TuioTime argument and assigns it along with the provided + * Session ID, Symbol ID, X and Y coordinate and angle to the newly created TuioObject. + * + * @param ttime the TuioTime to assign + * @param si the Session ID to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + TuioObject (TuioTime ttime, long si, int sym, float xp, float yp, float a); + + /** + * This constructor takes the provided Session ID, Symbol ID, X and Y coordinate + * and angle, and assigs these values to the newly created TuioObject. + * + * @param si the Session ID to assign + * @param sym the Symbol ID to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle to assign + */ + TuioObject (long si, int sym, float xp, float yp, float a); + + /** + * This constructor takes the atttibutes of the provided TuioObject + * and assigs these values to the newly created TuioObject. + * + * @param tobj the TuioObject to assign + */ + TuioObject (TuioObject *tobj); + + /** + * The destructor is doing nothing in particular. + */ + virtual ~TuioObject() { + if (angleFilter) delete angleFilter; + }; + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate, angle, X and Y velocity, motion acceleration, + * rotation speed and rotation acceleration to the private TuioObject attributes. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle coordinate to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param rs the rotation velocity to assign + * @param ma the motion acceleration to assign + * @param ra the rotation acceleration to assign + */ + void update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); + + /** + * Assigns the provided X and Y coordinate, angle, X and Y velocity, motion acceleration + * rotation velocity and rotation acceleration to the private TuioContainer attributes. + * The TuioTime time stamp remains unchanged. + * + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle coordinate to assign + * @param xs the X velocity to assign + * @param ys the Y velocity to assign + * @param rs the rotation velocity to assign + * @param ma the motion acceleration to assign + * @param ra the rotation acceleration to assign + */ + void update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); + + /** + * Takes a TuioTime argument and assigns it along with the provided + * X and Y coordinate and angle to the private TuioObject attributes. + * The speed and accleration values are calculated accordingly. + * + * @param ttime the TuioTime to assign + * @param xp the X coordinate to assign + * @param yp the Y coordinate to assign + * @param a the angle coordinate to assign + */ + void update (TuioTime ttime, float xp, float yp, float a); + + /** + * This method is used to calculate the speed and acceleration values of a + * TuioObject with unchanged position and angle. + */ + void stop (TuioTime ttime); + + /** + * Takes the atttibutes of the provided TuioObject + * and assigs these values to this TuioObject. + * The TuioTime time stamp of this TuioContainer remains unchanged. + * + * @param tobj the TuioContainer to assign + */ + void update (TuioObject *tobj); + + /** + * Returns the symbol ID of this TuioObject. + * @return the symbol ID of this TuioObject + */ + int getSymbolID() const; + + /** + * Returns the rotation angle of this TuioObject. + * @return the rotation angle of this TuioObject + */ + float getAngle() const; + + /** + * Returns the accumulated rotation angle of this TuioObject. + * @return the accumulated rotation angle of this TuioObject + */ + float getAngleSum() const; + + /** + * Returns the rotation angle in degrees of this TuioObject. + * @return the rotation angle in degrees of this TuioObject + */ + float getAngleDegrees() const; + + /** + * Returns the rotation speed of this TuioObject. + * @return the rotation speed of this TuioObject + */ + float getRotationSpeed() const; + + /** + * Returns the rotation acceleration of this TuioObject. + * @return the rotation acceleration of this TuioObject + */ + float getRotationAccel() const; + + /** + * Returns true of this TuioObject is moving. + * @return true of this TuioObject is moving + */ + bool isMoving() const; + + void addAngleThreshold(float thresh); + + void removeAngleThreshold(); + + void addAngleFilter(float mcut, float beta); + + void removeAngleFilter(); + }; +} +#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.cpp b/modules/touch/ext/libTUIO/TUIO/TuioPoint.cpp similarity index 62% rename from modules/touch/ext/libTUIO2/TUIO2/TuioPoint.cpp rename to modules/touch/ext/libTUIO/TUIO/TuioPoint.cpp index 935a63db77..0b0761c435 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.cpp +++ b/modules/touch/ext/libTUIO/TUIO/TuioPoint.cpp @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,13 +18,18 @@ #include "TuioPoint.h" -using namespace TUIO2; +using namespace TUIO; TuioPoint::TuioPoint (float xp, float yp) { xpos = xp; ypos = yp; - currentTime = TuioTime::getSystemTime(); + currentTime = TuioTime::getSessionTime(); startTime = currentTime; + + xposFilter = NULL; + yposFilter = NULL; + + posThreshold = 0.0f; } TuioPoint::TuioPoint (TuioTime ttime, float xp, float yp) { @@ -32,13 +37,23 @@ TuioPoint::TuioPoint (TuioTime ttime, float xp, float yp) { ypos = yp; currentTime = ttime; startTime = currentTime; + + xposFilter = NULL; + yposFilter = NULL; + + posThreshold = 0.0f; } TuioPoint::TuioPoint (TuioPoint *tpoint) { xpos = tpoint->getX(); ypos = tpoint->getY(); - currentTime = TuioTime::getSystemTime(); + currentTime = TuioTime::getSessionTime(); startTime = currentTime; + + xposFilter = NULL; + yposFilter = NULL; + + posThreshold = 0.0f; } void TuioPoint::update (TuioPoint *tpoint) { @@ -49,16 +64,30 @@ void TuioPoint::update (TuioPoint *tpoint) { void TuioPoint::update (float xp, float yp) { xpos = xp; ypos = yp; -} +} void TuioPoint::update (TuioTime ttime, float xp, float yp) { - xpos = xp; - ypos = yp; + + if (xposFilter && yposFilter) { + TuioTime diffTime = ttime - startTime; + float dt = diffTime.getTotalMilliseconds()/1000.0f; + xp = xposFilter->filter(xp,dt); + yp = yposFilter->filter(yp,dt); + //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; + } + + float dx = fabs(xpos - xp); + float dy = fabs(ypos - yp); + if ((dx>posThreshold) || (dy>posThreshold)) { + xpos = xp; + ypos = yp; + } + currentTime = ttime; } -float TuioPoint::getX() const{ +float TuioPoint::getX() const{ return xpos; } @@ -87,10 +116,10 @@ float TuioPoint::getAngle(float xp, float yp) const{ float side = xpos-xp; float height = ypos-yp; float distance = getDistance(xp,yp); - + float angle = (float)(asin(side/distance)+M_PI/2); if (height<0) angle = 2.0f*(float)M_PI-angle; - + return angle; } @@ -106,7 +135,7 @@ float TuioPoint::getAngleDegrees(TuioPoint *tpoint) const{ return ((getAngle(tpoint)/(float)M_PI)*180.0f); } -int TuioPoint::getScreenX(int width) const{ +int TuioPoint::getScreenX(int width) const{ return (int)floor(xpos*width+0.5f); } @@ -114,7 +143,7 @@ int TuioPoint::getScreenY(int height) const{ return (int)floor(ypos*height+0.5f); } -TuioTime TuioPoint::getTuioTime() const{ +TuioTime TuioPoint::getTuioTime() const{ return currentTime; } @@ -122,3 +151,26 @@ TuioTime TuioPoint::getStartTime() const{ return startTime; } +void TuioPoint::addPositionThreshold(float thresh) { + posThreshold = thresh; +} + +void TuioPoint::removePositionThreshold() { + posThreshold = 0.0f; +} + +void TuioPoint::addPositionFilter(float mcut, float beta) { + + if (xposFilter) delete xposFilter; + xposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); + if (yposFilter) delete yposFilter; + yposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); +} + +void TuioPoint::removePositionFilter() { + + if (xposFilter) delete xposFilter; + xposFilter = NULL; + if (yposFilter) delete yposFilter; + yposFilter = NULL; +} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h b/modules/touch/ext/libTUIO/TUIO/TuioPoint.h similarity index 85% rename from modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h rename to modules/touch/ext/libTUIO/TUIO/TuioPoint.h index a66730eb64..3415f07312 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioPoint.h +++ b/modules/touch/ext/libTUIO/TUIO/TuioPoint.h @@ -1,17 +1,17 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. - + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with this library. */ @@ -20,22 +20,22 @@ #define INCLUDED_TUIOPOINT_H #include "TuioTime.h" -#include "limits.h" +#include "OneEuroFilter.h" #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif -namespace TUIO2 { +namespace TUIO { /** - * The TuioPoint class on the one hand is a simple tobj and utility class to handle TUIO positions in general, - * on the other hand the TuioPoint is the base class for the TuioPointer and TuioToken classes. + * The TuioPoint class on the one hand is a simple container and utility class to handle TUIO positions in general, + * on the other hand the TuioPoint is the base class for the TuioCursor and TuioObject classes. * * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ + * @version 1.1.6 + */ class LIBDECL TuioPoint { protected: @@ -55,19 +55,20 @@ namespace TUIO2 { * The creation time of this TuioPoint represented as TuioTime (time since session start) */ TuioTime startTime; - + + OneEuroFilter *xposFilter; + OneEuroFilter *yposFilter; + float posThreshold; + public: - /** - * This constructor takes two floating point coordinate arguments - * and sets the coordinate attributes to these values. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - TuioPoint (float xp, float yp); - /** - * This constructor takes a TuioTime object and two floating point coordinate arguments and sets + * The default constructor takes no arguments and sets + * its coordinate attributes to zero and its time stamp to the current session time. + */ + TuioPoint (float xp, float yp); + + /** + * This constructor takes a TuioTime object and two floating point coordinate arguments and sets * its coordinate attributes to these values and its time stamp to the provided TUIO time object. * * @param ttime the TuioTime to assign @@ -75,37 +76,40 @@ namespace TUIO2 { * @param yp the Y coordinate to assign */ TuioPoint (TuioTime ttime, float xp, float yp); - + /** - * This constructor takes a TuioPoint argument and sets its coordinate attributes + * This constructor takes a TuioPoint argument and sets its coordinate attributes * to the coordinates of the provided TuioPoint and its time stamp to the current session time. * * @param tpoint the TuioPoint to assign */ TuioPoint (TuioPoint *tpoint); - + /** - * The destructor is doing nothing in particular. + * The destructor is doing nothing in particular. */ - ~TuioPoint(){}; - + virtual ~TuioPoint(){ + if (xposFilter) delete xposFilter; + if (yposFilter) delete yposFilter; + }; + /** - * Takes a TuioPoint argument and updates its coordinate attributes + * Takes a TuioPoint argument and updates its coordinate attributes * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. * * @param tpoint the TuioPoint to assign */ void update (TuioPoint *tpoint); - + /** * Takes two floating point coordinate arguments and updates its coordinate attributes * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. * * @param xp the X coordinate to assign * @param yp the Y coordinate to assign - */ - void update (float xp, float yp); - + */ + void update (float xp, float yp); + /** * Takes a TuioTime object and two floating point coordinate arguments and updates its coordinate attributes * to the coordinates of the provided TuioPoint and its time stamp to the provided TUIO time object. @@ -115,7 +119,8 @@ namespace TUIO2 { * @param yp the Y coordinate to assign */ void update (TuioTime ttime, float xp, float yp); - + + /** * Returns the X coordinate of this TuioPoint. * @return the X coordinate of this TuioPoint @@ -208,6 +213,14 @@ namespace TUIO2 { * @return the start time of this TuioPoint as TuioTime */ TuioTime getStartTime() const; + + void addPositionThreshold(float thresh); + + void removePositionThreshold(); + + void addPositionFilter(float mcut, float beta); + + void removePositionFilter(); }; } #endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioServer.cpp b/modules/touch/ext/libTUIO/TUIO/TuioServer.cpp new file mode 100644 index 0000000000..c157e7dc09 --- /dev/null +++ b/modules/touch/ext/libTUIO/TUIO/TuioServer.cpp @@ -0,0 +1,634 @@ +/* + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3.0 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. +*/ + +#include "TuioServer.h" +#include "UdpSender.h" + +using namespace TUIO; +using namespace osc; + +TuioServer::TuioServer() + :full_update (false) + ,periodic_update (false) + ,objectProfileEnabled (true) + ,cursorProfileEnabled (true) + ,blobProfileEnabled (true) + ,source_name (NULL) +{ + OscSender *oscsend = new UdpSender(); + initialize(oscsend); +} + +TuioServer::TuioServer(const char *host, int port) +:full_update (false) +,periodic_update (false) +,objectProfileEnabled (true) +,cursorProfileEnabled (true) +,blobProfileEnabled (true) +,source_name (NULL) +{ + OscSender *oscsend = new UdpSender(host,port); + initialize(oscsend); +} + +TuioServer::TuioServer(OscSender *oscsend) + :full_update (false) + ,periodic_update (false) + ,objectProfileEnabled (true) + ,cursorProfileEnabled (true) + ,blobProfileEnabled (true) + ,source_name (NULL) +{ + initialize(oscsend); +} + +void TuioServer::initialize(OscSender *oscsend) { + + senderList.push_back(oscsend); + int size = oscsend->getBufferSize(); + oscBuffer = new char[size]; + oscPacket = new osc::OutboundPacketStream(oscBuffer,size); + fullBuffer = new char[size]; + fullPacket = new osc::OutboundPacketStream(oscBuffer,size); + + objectUpdateTime = TuioTime(currentFrameTime); + cursorUpdateTime = TuioTime(currentFrameTime); + blobUpdateTime = TuioTime(currentFrameTime); + + if (cursorProfileEnabled) sendEmptyCursorBundle(); + if (objectProfileEnabled) sendEmptyObjectBundle(); + if (blobProfileEnabled) sendEmptyBlobBundle(); + + invert_x = false; + invert_y = false; + invert_a = false; +} + +TuioServer::~TuioServer() { + + initFrame(TuioTime::getSessionTime()); + stopUntouchedMovingCursors(); + stopUntouchedMovingObjects(); + stopUntouchedMovingBlobs(); + + initFrame(TuioTime::getSessionTime()); + removeUntouchedStoppedCursors(); + removeUntouchedStoppedObjects(); + removeUntouchedStoppedBlobs(); + + if (cursorProfileEnabled) sendEmptyCursorBundle(); + if (objectProfileEnabled) sendEmptyObjectBundle(); + if (blobProfileEnabled) sendEmptyBlobBundle(); + + delete []oscBuffer; + delete oscPacket; + delete []fullBuffer; + delete fullPacket; + + if (source_name) delete[] source_name; + for (unsigned int i=0;iisLocal()) && (senderList.size()==1)) { + setSourceName(source_name); + }*/ + + // resize packets to smallest transport method + unsigned int size = sender->getBufferSize(); + if (sizeCapacity()) { + osc::OutboundPacketStream *temp = oscPacket; + oscPacket = new osc::OutboundPacketStream(oscBuffer,size); + delete temp; + temp = fullPacket; + fullPacket = new osc::OutboundPacketStream(oscBuffer,size); + delete temp; + + } + + senderList.push_back(sender); +} + +void TuioServer::deliverOscPacket(osc::OutboundPacketStream *packet) { + + for (unsigned int i=0;isendOscPacket(packet); +} + +void TuioServer::setSourceName(const char *name, const char *ip) { + if (!source_name) source_name = new char[256]; + sprintf(source_name,"%s@%s",name,ip); +} + + +void TuioServer::setSourceName(const char *src) { + + if (!source_name) source_name = new char[256]; + + /*if (senderList[0]->isLocal()) { + sprintf(source_name,"%s",src); + } else {*/ + char hostname[64]; + char *source_addr = NULL; + struct hostent *hp = NULL; + struct in_addr *addr = NULL; + + gethostname(hostname, 64); + hp = gethostbyname(hostname); + + if (hp==NULL) { + sprintf(hostname, "%s.local", hostname); + hp = gethostbyname(hostname); + } + + if (hp!=NULL) { + for (int i = 0; hp->h_addr_list[i] != 0; ++i) { + addr = (struct in_addr *)(hp->h_addr_list[i]); + //std::cout << inet_ntoa(*addr) << std::endl; + source_addr = inet_ntoa(*addr); + } + } else { + //generate a random internet address + srand ( (unsigned int)time(NULL) ); + int32 r = rand(); + addr = (struct in_addr*)&r; + source_addr = inet_ntoa(*addr); + } + sprintf(source_name,"%s@%s",src,source_addr); + //} + + std::cout << "tuio/src " << source_name << std::endl; +} + +void TuioServer::commitFrame() { + TuioManager::commitFrame(); + + if(updateObject) { + startObjectBundle(); + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { + + // start a new packet if we exceed the packet capacity + if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addObjectMessage(tobj); + } + objectUpdateTime = TuioTime(currentFrameTime); + sendObjectBundle(currentFrame); + } else if (objectProfileEnabled && periodic_update) { + + TuioTime timeCheck = currentFrameTime - objectUpdateTime; + if(timeCheck.getSeconds()>=update_interval) { + objectUpdateTime = TuioTime(currentFrameTime); + startObjectBundle(); + if (full_update) { + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { + // start a new packet if we exceed the packet capacity + if ((oscPacket->Capacity()-oscPacket->Size())::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { + + // start a new packet if we exceed the packet capacity + if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addCursorMessage(tcur); + } + cursorUpdateTime = TuioTime(currentFrameTime); + sendCursorBundle(currentFrame); + } else if (cursorProfileEnabled && periodic_update) { + TuioTime timeCheck = currentFrameTime - cursorUpdateTime; + if(timeCheck.getSeconds()>=update_interval) { + cursorUpdateTime = TuioTime(currentFrameTime); + startCursorBundle(); + if (full_update) { + for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { + // start a new packet if we exceed the packet capacity + if ((oscPacket->Capacity()-oscPacket->Size())::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { + // start a new packet if we exceed the packet capacity + if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addBlobMessage(tblb); + } + blobUpdateTime = TuioTime(currentFrameTime); + sendBlobBundle(currentFrame); + } else if (blobProfileEnabled && periodic_update) { + TuioTime timeCheck = currentFrameTime - blobUpdateTime; + if(timeCheck.getSeconds()>=update_interval) { + blobUpdateTime = TuioTime(currentFrameTime); + startBlobBundle(); + if (full_update) { + for (std::list::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { + + // start a new packet if we exceed the packet capacity + if ((oscPacket->Capacity()-oscPacket->Size())Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive" << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage; + (*oscPacket) << osc::EndBundle; + deliverOscPacket( oscPacket ); +} + +void TuioServer::startCursorBundle() { + oscPacket->Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; + for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { + if ((*tuioCursor)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioCursor)->getSessionID()); + } + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::addCursorMessage(TuioCursor *tcur) { + + if (tcur->getTuioState()==TUIO_ADDED) return; + + float xpos = tcur->getX(); + float xvel = tcur->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = tcur->getY(); + float yvel = tcur->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + + (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set"; + (*oscPacket) << (int32)(tcur->getSessionID()) << xpos << ypos; + (*oscPacket) << xvel << yvel << tcur->getMotionAccel(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::sendCursorBundle(long fseq) { + (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << (int32)fseq << osc::EndMessage; + (*oscPacket) << osc::EndBundle; + deliverOscPacket( oscPacket ); +} + +void TuioServer::sendEmptyObjectBundle() { + oscPacket->Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive" << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage; + (*oscPacket) << osc::EndBundle; + deliverOscPacket( oscPacket ); +} + +void TuioServer::startObjectBundle() { + oscPacket->Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { + (*oscPacket) << (int32)((*tuioObject)->getSessionID()); + } + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::addObjectMessage(TuioObject *tobj) { + + float xpos = tobj->getX(); + float xvel = tobj->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = tobj->getY(); + float yvel = tobj->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + float angle = tobj->getAngle(); + float rvel = tobj->getRotationSpeed(); + if (invert_a) { + angle = 2.0f*(float)M_PI - angle; + rvel = -1 * rvel; + } + + (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set"; + (*oscPacket) << (int32)(tobj->getSessionID()) << tobj->getSymbolID() << xpos << ypos << angle; + (*oscPacket) << xvel << yvel << rvel << tobj->getMotionAccel() << tobj->getRotationAccel(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::sendObjectBundle(long fseq) { + (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << (int32)fseq << osc::EndMessage; + (*oscPacket) << osc::EndBundle; + deliverOscPacket( oscPacket ); +} + + +void TuioServer::sendEmptyBlobBundle() { + oscPacket->Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive" << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage; + (*oscPacket) << osc::EndBundle; + deliverOscPacket( oscPacket ); +} + +void TuioServer::startBlobBundle() { + oscPacket->Clear(); + (*oscPacket) << osc::BeginBundleImmediate; + if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; + (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; + for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { + if ((*tuioBlob)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioBlob)->getSessionID()); + } + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::addBlobMessage(TuioBlob *tblb) { + + if (tblb->getTuioState()==TUIO_ADDED) return; + + float xpos = tblb->getX(); + float xvel = tblb->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = tblb->getY(); + float yvel = tblb->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + float angle = tblb->getAngle(); + float rvel = tblb->getRotationSpeed(); + if (invert_a) { + angle = 2.0f*(float)M_PI - angle; + rvel = -1 * rvel; + } + + (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set"; + (*oscPacket) << (int32)(tblb->getSessionID()) << xpos << ypos << angle << tblb->getWidth() << tblb->getHeight() << tblb->getArea(); + (*oscPacket) << xvel << yvel << rvel << tblb->getMotionAccel() << tblb->getRotationAccel(); + (*oscPacket) << osc::EndMessage; +} + +void TuioServer::sendBlobBundle(long fseq) { + (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << (int32)fseq << osc::EndMessage; + (*oscPacket) << osc::EndBundle; + + deliverOscPacket( oscPacket ); +} + +void TuioServer::sendFullMessages() { + + // prepare the cursor packet + fullPacket->Clear(); + (*fullPacket) << osc::BeginBundleImmediate; + if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; + // add the cursor alive message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; + for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) + (*fullPacket) << (int32)((*tuioCursor)->getSessionID()); + (*fullPacket) << osc::EndMessage; + + // add all current cursor set messages + for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { + + // start a new packet if we exceed the packet capacity + if ((fullPacket->Capacity()-fullPacket->Size())Clear(); + (*fullPacket) << osc::BeginBundleImmediate; + if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; + // add the cursor alive message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; + for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) + (*fullPacket) << (int32)((*tuioCursor)->getSessionID()); + (*fullPacket) << osc::EndMessage; + } + + float xpos = (*tuioCursor)->getX(); + float xvel = (*tuioCursor)->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = (*tuioCursor)->getY(); + float yvel = (*tuioCursor)->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + + // add the actual cursor set message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set"; + (*fullPacket) << (int32)((*tuioCursor)->getSessionID()) << xpos << ypos; + (*fullPacket) << xvel << yvel <<(*tuioCursor)->getMotionAccel(); + (*fullPacket) << osc::EndMessage; + } + + // add the immediate fseq message and send the cursor packet + (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage; + (*fullPacket) << osc::EndBundle; + deliverOscPacket( fullPacket ); + + // prepare the object packet + fullPacket->Clear(); + (*fullPacket) << osc::BeginBundleImmediate; + if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; + // add the object alive message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) + (*fullPacket) << (int32)((*tuioObject)->getSessionID()); + (*fullPacket) << osc::EndMessage; + + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { + + // start a new packet if we exceed the packet capacity + if ((fullPacket->Capacity()-fullPacket->Size())Clear(); + (*fullPacket) << osc::BeginBundleImmediate; + if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; + // add the object alive message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; + for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) + (*fullPacket) << (int32)((*tuioObject)->getSessionID()); + (*fullPacket) << osc::EndMessage; + } + + float xpos = (*tuioObject)->getX(); + float xvel = (*tuioObject)->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = (*tuioObject)->getY(); + float yvel = (*tuioObject)->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + float angle = (*tuioObject)->getAngle(); + float rvel = (*tuioObject)->getRotationSpeed(); + if (invert_a) { + angle = 2.0f*(float)M_PI - angle; + rvel = -1 * rvel; + } + + // add the actual object set message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set"; + (*fullPacket) << (int32)((*tuioObject)->getSessionID()) << (*tuioObject)->getSymbolID() << xpos << ypos << angle; + (*fullPacket) << xvel << yvel << rvel << (*tuioObject)->getMotionAccel() << (*tuioObject)->getRotationAccel(); + (*fullPacket) << osc::EndMessage; + + } + // add the immediate fseq message and send the object packet + (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage; + (*fullPacket) << osc::EndBundle; + deliverOscPacket( fullPacket ); + + // prepare the blob packet + fullPacket->Clear(); + (*fullPacket) << osc::BeginBundleImmediate; + if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; + // add the object alive message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; + for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) + (*fullPacket) << (int32)((*tuioBlob)->getSessionID()); + (*fullPacket) << osc::EndMessage; + + for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { + + // start a new packet if we exceed the packet capacity + if ((fullPacket->Capacity()-fullPacket->Size())Clear(); + (*fullPacket) << osc::BeginBundleImmediate; + if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; + // add the blob alive message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; + for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) + (*fullPacket) << (int32)((*tuioBlob)->getSessionID()); + (*fullPacket) << osc::EndMessage; + } + + float xpos = (*tuioBlob)->getX(); + float xvel = (*tuioBlob)->getXSpeed(); + if (invert_x) { + xpos = 1 - xpos; + xvel = -1 * xvel; + } + float ypos = (*tuioBlob)->getY(); + float yvel = (*tuioBlob)->getYSpeed(); + if (invert_y) { + ypos = 1 - ypos; + yvel = -1 * yvel; + } + float angle = (*tuioBlob)->getAngle(); + float rvel = (*tuioBlob)->getRotationSpeed(); + if (invert_a) { + angle = 2.0f*(float)M_PI - angle; + rvel = -1 * rvel; + } + + // add the actual blob set message + (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set"; + (*fullPacket) << (int32)((*tuioBlob)->getSessionID()) << xpos << ypos << angle << (*tuioBlob)->getWidth() << (*tuioBlob)->getHeight() << (*tuioBlob)->getArea(); + (*fullPacket) << xvel << yvel << rvel << (*tuioBlob)->getMotionAccel() << (*tuioBlob)->getRotationAccel(); + (*fullPacket) << osc::EndMessage; + + } + // add the immediate fseq message and send the blob packet + (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage; + (*fullPacket) << osc::EndBundle; + deliverOscPacket( fullPacket ); +} + + + diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioServer.h b/modules/touch/ext/libTUIO/TUIO/TuioServer.h similarity index 53% rename from modules/touch/ext/libTUIO2/TUIO2/TuioServer.h rename to modules/touch/ext/libTUIO/TUIO/TuioServer.h index fc93f8b739..66ad0a574f 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioServer.h +++ b/modules/touch/ext/libTUIO/TUIO/TuioServer.h @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -16,11 +16,14 @@ License along with this library. */ -#ifndef INCLUDED_TUIOSERVER_H -#define INCLUDED_TUIOSERVER_H +#ifndef INCLUDED_TuioServer_H +#define INCLUDED_TuioServer_H #include "TuioManager.h" #include "UdpSender.h" +#include "TcpSender.h" +#include "WebSockSender.h" +#include "FlashSender.h" #include #include #include @@ -30,46 +33,40 @@ #include #endif -#define TOK_MESSAGE_SIZE 108 -#define PTR_MESSAGE_SIZE 68 -#define BND_MESSAGE_SIZE 116 -#define SYM_MESSAGE_SIZE 116 -#define ALV_MESSAGE_SIZE 20 - -namespace TUIO2 { +namespace TUIO { /** *

The TuioServer class is the central TUIO protocol encoder component. * In order to encode and send TUIO messages an instance of TuioServer needs to be created. The TuioServer instance then generates TUIO messages * which are deliverered by the provided OSCSender. The shown UDPSender send OSC to UDP port 3333 on localhost or to the configured host and port.

*

During runtime the each frame is marked with the initFrame and commitFrame methods, - * while the currently present TuioTokens are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

+ * while the currently present TuioObjects are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

*

See the SimpleSimulator example project for further hints on how to use the TuioServer class and its various methods. *

* OscSender *sender = new UDPSender();
* TuioServer *server = new TuioServer(sender);
- * server->setSource(src); // passes a TuioSource* argument
+ * server->setSourceName("MyTuioSource"); // optional for TUIO 1.1
* ...
- * server->initTuioFrame(TuioTime::getSessionTime());
- * TuioToken *ttok = server->addTuioToken(xpos,ypos,angle);
- * TuioPointer *tptr = server->addTuioPointer(xpos,ypos,width,pressure);
- * TuioBounds *tbnd = server->addTuioBounds(xpos,ypos,angle,width,height,area);
- * server->commitTuioFrame();
+ * server->initFrame(TuioTime::getSessionTime());
+ * TuioObject *tobj = server->addTuioObject(xpos,ypos,angle);
+ * TuioCursor *tcur = server->addTuiCursor(xpos,ypos);
+ * TuioBlob *tblb = server->addTuioBlob(xpos,ypos,angle,width,height, area);
+ * server->commitFrame();
* ...
- * server->initTuioFrame(TuioTime::getSessionTime());
- * server->updateTuioToken(ttok,xpos,ypos,angle);
- * server->updateTuioPointer(tptr,xpos,ypos,width,pressure);
- * server->updateTuioBounds(tbnd,xpos,ypos,angle,width,height,area);
- * server->commitTuioFrame();
+ * server->initFrame(TuioTime::getSessionTime());
+ * server->updateTuioObject(tobj,xpos,ypos,angle);
+ * server->updateTuioCursor(tcur,xpos,ypos);
+ * server->updateTuioBlob(tblb,xpos,ypos,angle,width,height,area);
+ * server->commitFrame();
* ...
- * server->initTuioFrame(TuioTime::getSessionTime());
- * server->removeTuioToken(ttok);
- * server->removeTuioPointer(tptr);
- * server->removeTuioBounds(tbnd);
- * server->commitTuioFrame();
+ * server->initFrame(TuioTime::getSessionTime());
+ * server->removeTuioObject(tobj);
+ * server->removeTuioCursor(tcur);
+ * server->removeTuioBlob(tblb);
+ * server->commitFrame();
*

* * @author Martin Kaltenbrunner - * @version 2.0.a0 + * @version 1.1.6 */ class LIBDECL TuioServer : public TuioManager { @@ -86,7 +83,7 @@ namespace TUIO2 { * @param host the host name for UDP deleivery * @param port the UDP port number on the provided host */ - TuioServer(const char *host, unsigned short port); + TuioServer(const char *host, int port); /** * This constructor creates a TuioServer that sends OSC data using the provided OscSender @@ -101,12 +98,12 @@ namespace TUIO2 { ~TuioServer(); /** - * Generates and sends TUIO messages of all currently active TUIO Components + * Generates and sends TUIO messages of all currently active TuioObjects, TuioCursors and TuioBlobs */ - void sendFullTuioBundle(); + void sendFullMessages(); /** - * Enables the full update of all currently active and inactive TUIO Components + * Enables the full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs * */ void enableFullUpdate() { @@ -114,22 +111,22 @@ namespace TUIO2 { } /** - * Disables the full update of all currently active and inactive TUIO Components + * Disables the full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs */ void disableFullUpdate() { full_update = false; } /** - * Returns true if the full update of all currently active TUIO Components is enabled. - * @return true if the full update of all currently active TUIO Components is enabled + * Returns true if the full update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled. + * @return true if the full update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled */ bool fullUpdateEnabled() { return full_update; } /** - * Disables the periodic full update of all currently active TUIO Components + * Disables the periodic full update of all currently active TuioObjects TuioObjects, TuioCursors and TuioBlobs * * @param interval update interval in seconds, defaults to one second */ @@ -139,15 +136,15 @@ namespace TUIO2 { } /** - * Disables the periodic full update of all currently active and inactive TUIO Components + * Disables the periodic full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs */ void disablePeriodicMessages() { periodic_update = false; } /** - * Returns true if the periodic update of all currently active TUIO Components is enabled. - * @return true if the periodic update of all currently active TUIO Components is enabled + * Returns true if the periodic update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled. + * @return true if the periodic update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled */ bool periodicMessagesEnabled() { return periodic_update; @@ -163,48 +160,71 @@ namespace TUIO2 { /** * Commits the current frame. - * Generates and sends TUIO messages of all currently active and updated TUIO Components. + * Generates and sends TUIO messages of all currently active and updated TuioObjects, TuioCursors and TuioBlobs. + */ + void commitFrame(); + + /** + * Commits the current frame. + * Generates and sends TUIO messages of all currently active and updated TuioObjects, TuioCursors and TuioBlobs. */ - void commitTuioFrame(); /** - * Creates the TuioSource that is transmitted within the /tuio2/frm source attributes. + * Defines the name of this TUIO source, which is transmitted within the /tuio/[profile] source message. * - * @param name the source name to assign + * @param name the desired name of this TUIO source + */ + void setSourceName(const char *name); + + + /** + * Defines the name and IP address of this TUIO source, which is transmitted within the /tuio/[profile] source message. + * + * @param name the desired name of this TUIO source + * @param ip the local IP address */ - void setSourceName(const char* name); - void setDimension(unsigned short w, unsigned short h); + void setSourceName(const char *name, const char *ip); + + void addOscSender(OscSender *sender); + + void enableObjectProfile(bool flag) { objectProfileEnabled = flag; }; + void enableCursorProfile(bool flag) { cursorProfileEnabled = flag; }; + void enableBlobProfile(bool flag) { blobProfileEnabled = flag; }; private: - void initialize(); - - OscSender *primary_sender; - bool local_sender; + void initialize(OscSender *oscsend); std::vector senderList; void deliverOscPacket(osc::OutboundPacketStream *packet); - osc::OutboundPacketStream *oscPacket; + osc::OutboundPacketStream *oscPacket; char *oscBuffer; - osc::OutboundPacketStream *fullPacket; + osc::OutboundPacketStream *fullPacket; char *fullBuffer; - void checkBundleCapacity(int size); - void startTuioBundle(unsigned int fseq); - void addTokenMessage(TuioToken *ttok); - void addPointerMessage(TuioPointer *tptr); - void addBoundsMessage(TuioBounds *tbnd); - void addSymbolMessage(TuioSymbol *tsym); - void sendTuioBundle(); - void sendEmptyTuioBundle(); + void startObjectBundle(); + void addObjectMessage(TuioObject *tobj); + void sendObjectBundle(long fseq); + void sendEmptyObjectBundle(); + + void startCursorBundle(); + void addCursorMessage(TuioCursor *tcur); + void sendCursorBundle(long fseq); + void sendEmptyCursorBundle(); + + void startBlobBundle(); + void addBlobMessage(TuioBlob *tblb); + void sendBlobBundle(long fseq); + void sendEmptyBlobBundle(); int update_interval; bool full_update, periodic_update; - TuioTime updateTime; - TuioSource *source; + TuioTime objectUpdateTime, cursorUpdateTime, blobUpdateTime ; + bool objectProfileEnabled, cursorProfileEnabled, blobProfileEnabled; + char *source_name; }; } -#endif /* INCLUDED_TUIOSERVER_H */ +#endif /* INCLUDED_TuioServer_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp b/modules/touch/ext/libTUIO/TUIO/TuioTime.cpp similarity index 69% rename from modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp rename to modules/touch/ext/libTUIO/TUIO/TuioTime.cpp index b84af84458..f169c1451f 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioTime.cpp +++ b/modules/touch/ext/libTUIO/TUIO/TuioTime.cpp @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,7 @@ */ #include "TuioTime.h" -using namespace TUIO2; +using namespace TUIO; long TuioTime::start_seconds = 0; long TuioTime::start_micro_seconds = 0; @@ -26,15 +26,7 @@ TuioTime::TuioTime (long msec) { seconds = msec/MSEC_SECOND; micro_seconds = USEC_MILLISECOND*(msec%MSEC_SECOND); } - -TuioTime::TuioTime (osc::TimeTag timetag) { - osc::uint32 secs = timetag >> 32; - osc::uint32 frac = timetag & 0x00000000FFFFFFFF; - - seconds = secs - JAN_1970; - micro_seconds = frac / NTP_UNITS; -} - + TuioTime::TuioTime (long sec, long usec) { seconds = sec; micro_seconds = usec; @@ -96,10 +88,6 @@ bool TuioTime::operator!=(TuioTime ttime) { void TuioTime::reset() { seconds = 0; micro_seconds = 0; - - TuioTime system_time = getSystemTime(); - seconds = system_time.getSeconds(); - micro_seconds = system_time.getMicroseconds(); } long TuioTime::getSeconds() const{ @@ -114,26 +102,18 @@ long TuioTime::getTotalMilliseconds() const{ return seconds*MSEC_SECOND+micro_seconds/MSEC_SECOND; } -unsigned int TuioTime::getFrameID() const{ - return frame_id; -} - -void TuioTime::setFrameID(unsigned int f_id) { - frame_id = f_id; -} - -/*void TuioTime::initSession() { - TuioTime startTime = TuioTime::getSystemTime(); - start_seconds = startTime.getSeconds(); - start_micro_seconds = startTime.getMicroseconds(); +void TuioTime::initSession() { + TuioTime startTime = TuioTime::getSystemTime(); + start_seconds = startTime.getSeconds(); + start_micro_seconds = startTime.getMicroseconds(); } TuioTime TuioTime::getSessionTime() { - return (getSystemTime() - getStartTime()); -}*/ + return (getSystemTime() - getStartTime()); +} TuioTime TuioTime::getStartTime() { - return TuioTime(start_seconds,start_micro_seconds); + return TuioTime(start_seconds,start_micro_seconds); } TuioTime TuioTime::getSystemTime() { @@ -147,14 +127,3 @@ TuioTime TuioTime::getSystemTime() { #endif return systemTime; } - -osc::TimeTag TuioTime::getSystemTimeTag() { - - TuioTime systemTime = getSystemTime(); - - osc::uint32 secs = systemTime.getSeconds() + JAN_1970; - osc::uint32 frac = systemTime.getMicroseconds() * NTP_UNITS; - - osc::uint64 timetag = (osc::uint64) secs << 32 | frac; - return osc::TimeTag(timetag); -} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioTime.h b/modules/touch/ext/libTUIO/TUIO/TuioTime.h similarity index 81% rename from modules/touch/ext/libTUIO2/TUIO2/TuioTime.h rename to modules/touch/ext/libTUIO/TUIO/TuioTime.h index f1c1e10133..567c443fc1 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioTime.h +++ b/modules/touch/ext/libTUIO/TUIO/TuioTime.h @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -20,7 +20,6 @@ #define INCLUDED_TUIOTIME_H #include "LibExport.h" -#include "oscpack/osc/OscTypes.h" #ifndef WIN32 #include @@ -34,10 +33,7 @@ #define USEC_SECOND 1000000 #define USEC_MILLISECOND 1000 -#define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */ -#define NTP_UNITS 4294.967295 /* NTP units per second */ - -namespace TUIO2 { +namespace TUIO { /** * The TuioTime class is a simple structure that is used to reprent the time that has elapsed since the session start. @@ -47,7 +43,7 @@ namespace TUIO2 { * The class also provides various addtional convience method, which allow some simple time arithmetics. * * @author Martin Kaltenbrunner - * @version 2.0.a0 + * @version 1.1.6 */ class LIBDECL TuioTime { @@ -56,8 +52,6 @@ namespace TUIO2 { long micro_seconds; static long start_seconds; static long start_micro_seconds; - - unsigned int frame_id; public: @@ -65,7 +59,7 @@ namespace TUIO2 { * The default constructor takes no arguments and sets * the Seconds and Microseconds attributes of the newly created TuioTime both to zero. */ - TuioTime ():seconds(0),micro_seconds(0),frame_id(0) {}; + TuioTime ():seconds(0),micro_seconds(0) {}; /** * The destructor is doing nothing in particular. @@ -79,15 +73,6 @@ namespace TUIO2 { * @param msec the total time in Millseconds */ TuioTime (long msec); - - - /** - * This constructor takes the provided time in OSC format - * and assigs this value to the newly created TuioTime. - * - * @param tag the time in OSC format - */ - TuioTime (osc::TimeTag timetag); /** * This constructor takes the provided time represented in Seconds and Microseconds @@ -176,29 +161,17 @@ namespace TUIO2 { * @return the total TuioTime in Milliseconds */ long getTotalMilliseconds() const; - - /** - * Returns the assigned Frame ID. - * @return the assigned Frame ID - */ - unsigned int getFrameID() const; - /** - * assigns a Frame ID. - * @f_id the Frame ID to assign - */ - void setFrameID(unsigned int f_id); - /** * This static method globally resets the TUIO session time. */ - //static void initSession(); + static void initSession(); /** * Returns the present TuioTime representing the time since session start. * @return the present TuioTime representing the time since session start */ - //tatic TuioTime getSessionTime(); + static TuioTime getSessionTime(); /** * Returns the absolut TuioTime representing the session start. @@ -211,12 +184,6 @@ namespace TUIO2 { * @return the absolut TuioTime representing the current system time */ static TuioTime getSystemTime(); - - /** - * Returns the absolut TuioTime representing the current system time. - * @return the absolut TuioTime representing the current system time - */ - static osc::TimeTag getSystemTimeTag(); }; } #endif /* INCLUDED_TUIOTIME_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp b/modules/touch/ext/libTUIO/TUIO/UdpReceiver.cpp similarity index 91% rename from modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp rename to modules/touch/ext/libTUIO/TUIO/UdpReceiver.cpp index fe1b3ad952..38abac60ba 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.cpp +++ b/modules/touch/ext/libTUIO/TUIO/UdpReceiver.cpp @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -18,7 +18,7 @@ #include "UdpReceiver.h" -using namespace TUIO2; +using namespace TUIO; using namespace osc; #ifndef WIN32 @@ -31,7 +31,7 @@ static DWORD WINAPI ClientThreadFunc( LPVOID obj ) return 0; }; -UdpReceiver::UdpReceiver(unsigned short port):locked (false) { +UdpReceiver::UdpReceiver(int port):locked (false) { try { socket = new UdpListeningReceiveSocket(IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), this ); } catch (std::exception &e) { diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.h b/modules/touch/ext/libTUIO/TUIO/UdpReceiver.h similarity index 91% rename from modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.h rename to modules/touch/ext/libTUIO/TUIO/UdpReceiver.h index 026e09ae26..9d29b4255f 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/UdpReceiver.h +++ b/modules/touch/ext/libTUIO/TUIO/UdpReceiver.h @@ -1,6 +1,6 @@ /* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner + TUIO C++ Library + Copyright (c) 2005-2016 Martin Kaltenbrunner This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -22,13 +22,13 @@ #include "OscReceiver.h" #include "oscpack/ip/UdpSocket.h" -namespace TUIO2 { +namespace TUIO { /** * The UdpReceiver provides the OscReceiver functionality for the UDP transport method * * @author Martin Kaltenbrunner - * @version 2.0.a0 + * @version 1.1.6 */ class LIBDECL UdpReceiver: public OscReceiver { @@ -44,7 +44,7 @@ namespace TUIO2 { * * @param port the number of the UDP port to listen to, defaults to 3333 */ - UdpReceiver (unsigned short port=3333); + UdpReceiver (int port=3333); /** * The destructor is doing nothing in particular. diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpSender.cpp b/modules/touch/ext/libTUIO/TUIO/UdpSender.cpp similarity index 99% rename from modules/touch/ext/libTUIO2/TUIO2/UdpSender.cpp rename to modules/touch/ext/libTUIO/TUIO/UdpSender.cpp index 9a231a5617..c4f8c109d9 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/UdpSender.cpp +++ b/modules/touch/ext/libTUIO/TUIO/UdpSender.cpp @@ -18,7 +18,7 @@ #include "UdpSender.h" -using namespace TUIO2; +using namespace TUIO; UdpSender::UdpSender() { try { diff --git a/modules/touch/ext/libTUIO2/TUIO2/UdpSender.h b/modules/touch/ext/libTUIO/TUIO/UdpSender.h similarity index 98% rename from modules/touch/ext/libTUIO2/TUIO2/UdpSender.h rename to modules/touch/ext/libTUIO/TUIO/UdpSender.h index 9cd2eb722f..20927309c6 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/UdpSender.h +++ b/modules/touch/ext/libTUIO/TUIO/UdpSender.h @@ -26,14 +26,14 @@ #define MAX_UDP_SIZE 4096 #define MIN_UDP_SIZE 576 -namespace TUIO2 { +namespace TUIO { /** * The UdpSender implements the UDP transport method for OSC * * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ + * @version 1.1.6 + */ class LIBDECL UdpSender : public OscSender { public: diff --git a/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.cpp b/modules/touch/ext/libTUIO/TUIO/WebSockSender.cpp similarity index 99% rename from modules/touch/ext/libTUIO2/TUIO2/WebSockSender.cpp rename to modules/touch/ext/libTUIO/TUIO/WebSockSender.cpp index 781fcb5e75..3f4375fa78 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.cpp +++ b/modules/touch/ext/libTUIO/TUIO/WebSockSender.cpp @@ -26,7 +26,7 @@ #endif #endif -using namespace TUIO2; +using namespace TUIO; WebSockSender::WebSockSender() :TcpSender( 8080 ) @@ -114,6 +114,7 @@ void WebSockSender::newClient( int tcp_client ) { "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" + "Access-Control-Allow-Origin: *\r\n" "Sec-WebSocket-Accept: %s\r\n\r\n", base64( digest, SHA1_HASH_SIZE ).c_str() ); diff --git a/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.h b/modules/touch/ext/libTUIO/TUIO/WebSockSender.h similarity index 99% rename from modules/touch/ext/libTUIO2/TUIO2/WebSockSender.h rename to modules/touch/ext/libTUIO/TUIO/WebSockSender.h index 0cc9d12935..968b07a333 100644 --- a/modules/touch/ext/libTUIO2/TUIO2/WebSockSender.h +++ b/modules/touch/ext/libTUIO/TUIO/WebSockSender.h @@ -67,7 +67,7 @@ __inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) #include #include -namespace TUIO2 { +namespace TUIO { /** * The WebSockSender implements the WebSocket transport method for OSC diff --git a/modules/touch/ext/libTUIO2/oscpack/CHANGES b/modules/touch/ext/libTUIO/oscpack/CHANGES similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/CHANGES rename to modules/touch/ext/libTUIO/oscpack/CHANGES diff --git a/modules/touch/ext/libTUIO2/oscpack/LICENSE b/modules/touch/ext/libTUIO/oscpack/LICENSE similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/LICENSE rename to modules/touch/ext/libTUIO/oscpack/LICENSE diff --git a/modules/touch/ext/libTUIO2/oscpack/README b/modules/touch/ext/libTUIO/oscpack/README similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/README rename to modules/touch/ext/libTUIO/oscpack/README diff --git a/modules/touch/ext/libTUIO2/oscpack/TODO b/modules/touch/ext/libTUIO/oscpack/TODO similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/TODO rename to modules/touch/ext/libTUIO/oscpack/TODO diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.cpp b/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.cpp similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.cpp rename to modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.cpp diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.h b/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/IpEndpointName.h rename to modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.h diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/NetworkingUtils.h b/modules/touch/ext/libTUIO/oscpack/ip/NetworkingUtils.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/NetworkingUtils.h rename to modules/touch/ext/libTUIO/oscpack/ip/NetworkingUtils.h diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/PacketListener.h b/modules/touch/ext/libTUIO/oscpack/ip/PacketListener.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/PacketListener.h rename to modules/touch/ext/libTUIO/oscpack/ip/PacketListener.h diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/TimerListener.h b/modules/touch/ext/libTUIO/oscpack/ip/TimerListener.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/TimerListener.h rename to modules/touch/ext/libTUIO/oscpack/ip/TimerListener.h diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/UdpSocket.h b/modules/touch/ext/libTUIO/oscpack/ip/UdpSocket.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/UdpSocket.h rename to modules/touch/ext/libTUIO/oscpack/ip/UdpSocket.h diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/posix/NetworkingUtils.cpp b/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp similarity index 98% rename from modules/touch/ext/libTUIO2/oscpack/ip/posix/NetworkingUtils.cpp rename to modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp index 720abc207e..7f36605472 100644 --- a/modules/touch/ext/libTUIO2/oscpack/ip/posix/NetworkingUtils.cpp +++ b/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp @@ -34,7 +34,7 @@ requested that these non-binding requests be included whenever the above license is reproduced. */ -#include "oscpack/ip/NetworkingUtils.h" +#include "ip/NetworkingUtils.h" #include #include diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/posix/UdpSocket.cpp b/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp similarity index 99% rename from modules/touch/ext/libTUIO2/oscpack/ip/posix/UdpSocket.cpp rename to modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp index f0f1afbb78..b8262fcc99 100644 --- a/modules/touch/ext/libTUIO2/oscpack/ip/posix/UdpSocket.cpp +++ b/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp @@ -34,7 +34,7 @@ requested that these non-binding requests be included whenever the above license is reproduced. */ -#include "oscpack/ip/UdpSocket.h" +#include "ip/UdpSocket.h" #include #include @@ -57,8 +57,8 @@ #include #include -#include "oscpack/ip/PacketListener.h" -#include "oscpack/ip/TimerListener.h" +#include "ip/PacketListener.h" +#include "ip/TimerListener.h" #if defined(__APPLE__) && !defined(_SOCKLEN_T) diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/win32/NetworkingUtils.cpp b/modules/touch/ext/libTUIO/oscpack/ip/win32/NetworkingUtils.cpp similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/win32/NetworkingUtils.cpp rename to modules/touch/ext/libTUIO/oscpack/ip/win32/NetworkingUtils.cpp diff --git a/modules/touch/ext/libTUIO2/oscpack/ip/win32/UdpSocket.cpp b/modules/touch/ext/libTUIO/oscpack/ip/win32/UdpSocket.cpp similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/ip/win32/UdpSocket.cpp rename to modules/touch/ext/libTUIO/oscpack/ip/win32/UdpSocket.cpp diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/MessageMappingOscPacketListener.h b/modules/touch/ext/libTUIO/oscpack/osc/MessageMappingOscPacketListener.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/MessageMappingOscPacketListener.h rename to modules/touch/ext/libTUIO/oscpack/osc/MessageMappingOscPacketListener.h diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscException.h b/modules/touch/ext/libTUIO/oscpack/osc/OscException.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscException.h rename to modules/touch/ext/libTUIO/oscpack/osc/OscException.h diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscHostEndianness.h b/modules/touch/ext/libTUIO/oscpack/osc/OscHostEndianness.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscHostEndianness.h rename to modules/touch/ext/libTUIO/oscpack/osc/OscHostEndianness.h diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.cpp similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.cpp rename to modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.cpp diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.h b/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscOutboundPacketStream.h rename to modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.h diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscPacketListener.h b/modules/touch/ext/libTUIO/oscpack/osc/OscPacketListener.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscPacketListener.h rename to modules/touch/ext/libTUIO/oscpack/osc/OscPacketListener.h diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.cpp similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.cpp rename to modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.cpp diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.h b/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscPrintReceivedElements.h rename to modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.h diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.cpp similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.cpp rename to modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.cpp diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.h b/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscReceivedElements.h rename to modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.h diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.cpp similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.cpp rename to modules/touch/ext/libTUIO/oscpack/osc/OscTypes.cpp diff --git a/modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.h b/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.h similarity index 100% rename from modules/touch/ext/libTUIO2/oscpack/osc/OscTypes.h rename to modules/touch/ext/libTUIO/oscpack/osc/OscTypes.h diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp deleted file mode 100644 index bf2f1c8002..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioBounds.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioBounds.h" -using namespace TUIO2; - -TuioBounds::TuioBounds (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a, float w, float h, float f):TuioComponent(ttime, tobj, xp, yp,a) { - width = w; - height = h; - area = f; -} - -TuioBounds::TuioBounds (TuioObject *tobj, float xp, float yp, float a, float w, float h, float f):TuioComponent(tobj, xp, yp, a) { - width = w; - height = h; - area = f; -} - -TuioBounds::TuioBounds (TuioBounds *tbnd):TuioComponent(tbnd) { - angle = tbnd->getAngle(); - width = tbnd->getWidth(); - height = tbnd->getHeight(); - area = tbnd->getArea(); - rotation_speed = 0.0f; - rotation_accel = 0.0f; -} - -void TuioBounds::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { - TuioComponent::update(ttime,xp,yp,a,xs,ys,rs,ma,ra); - width = w; - height = h; - area = f; -} - -void TuioBounds::update (float xp, float yp, float a, float w, float h, float f, float xs, float ys, float rs, float ma, float ra) { - TuioComponent::update(xp,yp,a,xs,ys,rs,ma,ra); - width = w; - height = h; - area = f; -} - -void TuioBounds::update (TuioTime ttime, float xp, float yp, float a, float w, float h, float f) { - TuioComponent::update(ttime,xp,yp,a); - - width = w; - height = h; - area = f; -} - -void TuioBounds::stop (TuioTime ttime) { - update(ttime,xpos,ypos,angle,width,height,area); -} - -void TuioBounds::update (TuioBounds *tbnd) { - TuioComponent::update(tbnd); - width = tbnd->getWidth(); - height = tbnd->getHeight(); - area = tbnd->getArea(); -} - -float TuioBounds::getWidth() const{ - return width; -} - -float TuioBounds::getHeight() const{ - return height; -} - -int TuioBounds::getScreenWidth(int w) const{ - return (int)(w*width); -} - -int TuioBounds::getScreenHeight(int h) const{ - return (int)(h*height); -} - -float TuioBounds::getArea() const{ - return area; -} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp deleted file mode 100644 index e638651008..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioClient.cpp +++ /dev/null @@ -1,520 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioClient.h" -#include "UdpReceiver.h" - -using namespace TUIO2; -using namespace osc; - - -TuioClient::TuioClient() -: lateFrame (false) -, source_count (0) -, receiver (NULL) -, local_receiver(true) -{ - receiver = new UdpReceiver(); - initialize(); -} - -TuioClient::TuioClient(unsigned short port) -: lateFrame (false) -, source_count (0) -, receiver (NULL) -, local_receiver(true) -{ - receiver = new UdpReceiver(port); - initialize(); -} - -TuioClient::TuioClient(OscReceiver *osc) -: lateFrame (false) -, source_count (0) -, receiver (osc) -, local_receiver(false) -{ - initialize(); -} - -void TuioClient::initialize() { - receiver->addTuioClient(this); -} - -TuioClient::~TuioClient() { - if (local_receiver) delete receiver; -} - -void TuioClient::processOSC( const ReceivedMessage& msg ) { - try { - ReceivedMessageArgumentStream args = msg.ArgumentStream(); - //ReceivedMessage::const_iterator arg = msg.ArgumentsBegin(); - - if( strcmp( msg.AddressPattern(), "/tuio2/frm" ) == 0 ) { - //lockFrame(); - int32 fseq_raw,dim_raw; - TimeTag timetag; - const char* src_string; - args >> fseq_raw >> timetag >> dim_raw >> src_string; - - // check if we know that source - std::map::iterator iter = sourceList.find(src_string); - - if (iter==sourceList.end()) { // add a new source - frameSource = new TuioSource(source_count, src_string, (unsigned int)dim_raw); - sourceList[src_string] = frameSource; - source_count++; - } else { // use the found source - frameSource = sourceList[src_string]; - } - - unsigned int currentFrameID = (unsigned int)fseq_raw; - frameTime = TuioTime(timetag); - frameTime.setFrameID(currentFrameID); - - // frame sequence - lateFrame = false; - unsigned int lastFrameID = frameSource->getFrameTime().getFrameID(); - unsigned int timeDiff = frameTime.getTotalMilliseconds() - frameSource->getFrameTime().getTotalMilliseconds(); - frameSource->setFrameTime(frameTime); - - // drop late frames (but accept the reserved ID 0 and consider a possible reset after 1sec - if ((currentFrameID> s_id_raw >> tu_id_raw >> c_id_raw >> xpos >> ypos >> angle; - if (!args.Eos()) args >> xspeed >> yspeed >> rspeed >> maccel >> raccel; - else xspeed = yspeed = rspeed = maccel = raccel = 0.0f; - - s_id = (unsigned int)s_id_raw; - c_id = (unsigned int)c_id_raw; - t_id = tu_id_raw >> 16; - u_id = tu_id_raw & 0x0000FFFF; - - TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); - //if (tobj == NULL) std::cout << "new cont " << s_id << " " << frameSource.getSourceID() << std::endl; - if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); - addFrameObject(tobj); - TuioToken *ttok = tobj->getTuioToken(); - if (ttok == NULL) { - ttok = new TuioToken(frameTime,tobj,t_id,u_id,c_id,xpos,ypos,angle); - tobj->setTuioToken(ttok); - } else if ( (ttok->getX()!=xpos) || (ttok->getY()!=ypos) || (ttok->getAngle()!=angle) || (ttok->getXSpeed()!=xspeed) || (ttok->getYSpeed()!=yspeed) || (ttok->getRotationSpeed()!=rspeed) || (ttok->getMotionAccel()!=maccel) || (ttok->getRotationAccel()!=raccel) ) { - - ttok->update(frameTime,xpos,ypos,angle,xspeed,yspeed,rspeed,maccel,raccel); - } - - } else if( strcmp( msg.AddressPattern(), "/tuio2/ptr" ) == 0 ) { - - if (lateFrame) return; - int32 s_id_raw, tu_id_raw, c_id_raw; - unsigned short t_id, u_id; - unsigned int s_id,c_id; - float xpos, ypos, angle, shear,radius, pressure, xspeed, yspeed, pspeed, maccel, paccel; - args >> s_id_raw >> tu_id_raw >> c_id_raw >> xpos >> ypos >> angle >> shear >> radius >> pressure; - if (!args.Eos()) args >> xspeed >> yspeed >> pspeed >> maccel >> paccel; - else xspeed = yspeed = pspeed = maccel = paccel = 0.0f; - - s_id = (unsigned int)s_id_raw; - c_id = (unsigned int)c_id_raw; - t_id = tu_id_raw >> 16; - u_id = tu_id_raw & 0x0000FFFF; - - TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); - //if (tobj == NULL) std::cout << "new cont " << s_id << " " << frameSource.getSourceID() << std::endl; - if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); - addFrameObject(tobj); - TuioPointer *tptr = tobj->getTuioPointer(); - if (tptr == NULL) { - tptr = new TuioPointer(frameTime,tobj,t_id,u_id,c_id,xpos,ypos,angle,shear,radius,pressure); - tobj->setTuioPointer(tptr); - - } else if ( (tptr->getX()!=xpos) || (tptr->getY()!=ypos) || (tptr->getAngle()!=angle) || (tptr->getShear()!=shear) || (tptr->getRadius()!=radius) || (tptr->getPressure()!=pressure) || (tptr->getXSpeed()!=xspeed) || (tptr->getYSpeed()!=yspeed) || (tptr->getPressureSpeed()!=pspeed) || (tptr->getMotionAccel()!=maccel) || (tptr->getPressureAccel()!=paccel) ) { - - tptr->update(frameTime,xpos,ypos,angle,shear,radius,pressure,xspeed,yspeed,pspeed,maccel,paccel); - } - } else if( strcmp( msg.AddressPattern(), "/tuio2/bnd" ) == 0 ) { - - if (lateFrame) return; - int32 s_id_raw; - unsigned int s_id; - float xpos, ypos, angle, width, height, area; - float xspeed, yspeed, rspeed, maccel, raccel; - args >> s_id_raw >> xpos >> ypos >> angle >> width >> height >> area; - if (!args.Eos()) args >> xspeed >> yspeed >> rspeed >> maccel >> raccel; - else xspeed = yspeed = rspeed = maccel = raccel = 0.0f; - - s_id = (unsigned int)s_id_raw; - TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); - if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); - addFrameObject(tobj); - TuioBounds *tbnd = tobj->getTuioBounds(); - if (tbnd == NULL) { - tbnd = new TuioBounds(frameTime,tobj,xpos,ypos,angle,width,height,area); - tobj->setTuioBounds(tbnd); - } else if ( (tbnd->getX()!=xpos) || (tbnd->getY()!=ypos) || (tbnd->getAngle()!=angle) || (tbnd->getWidth()!=width) || (tbnd->getHeight()!=height) || (tbnd->getArea()!=area) || (tbnd->getXSpeed()!=xspeed) || (tbnd->getYSpeed()!=yspeed) || (tbnd->getRotationSpeed()!=rspeed) || (tbnd->getMotionAccel()!=maccel) || (tbnd->getRotationAccel()!=raccel)) { - - tbnd->update(frameTime,xpos,ypos,angle,width,height,area,xspeed,yspeed,rspeed,maccel,raccel); - } - } else if( strcmp( msg.AddressPattern(), "/tuio2/sym" ) == 0 ) { - - if (lateFrame) return; - int32 s_id_raw, tu_id_raw, c_id_raw; - unsigned int s_id, c_id; - unsigned short t_id, u_id; - const char* type; - const char* data; - args >> s_id_raw >> tu_id_raw >> c_id_raw >> type >> data; - - s_id = (unsigned int)s_id_raw; - c_id = (unsigned int)c_id_raw; - t_id = tu_id_raw >> 16; - u_id = tu_id_raw & 0x0000FFFF; - - TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); - if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); - addFrameObject(tobj); - TuioSymbol *tsym = tobj->getTuioSymbol(); - if (tsym == NULL) { - tsym = new TuioSymbol(frameTime,tobj,t_id,u_id,c_id,type,data); - tobj->setTuioSymbol(tsym); - } else { - tsym->update(frameTime); - } - - } else if( strcmp( msg.AddressPattern(), "/tuio2/chg" ) == 0 ) { - if (lateFrame) return; - int32 s_id_raw; - args >> s_id_raw; - unsigned int s_id = (unsigned int)s_id_raw; - - std::list pointList; - while(!args.Eos()) { - float xpos, ypos; - args >> xpos >> ypos; - pointList.push_back(TuioPoint(frameTime, xpos, ypos)); - } - - TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); - if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); - addFrameObject(tobj); - - /*TuioGeometry *tgeo = tobj->getTuioGeometry(); - if (tgeo == NULL) { - tgeo = new TuioGeometry(frameTime, tobj); - tobj->setTuioGeometry(tgeo); - } tgeo->setConvexHull(pointList);*/ - - } else if( strcmp( msg.AddressPattern(), "/tuio2/ocg" ) == 0 ) { - if (lateFrame) return; - int32 s_id_raw; - args >> s_id_raw; - unsigned int s_id = (unsigned int)s_id_raw; - - std::list pointList; - while(!args.Eos()) { - float xpos, ypos; - args >> xpos >> ypos; - pointList.push_back(TuioPoint(frameTime, xpos, ypos)); - } - - TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); - if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); - addFrameObject(tobj); - - /*TuioGeometry *tgeo = tobj->getTuioGeometry(); - if (tgeo == NULL) { - tgeo = new TuioGeometry(frameTime, tobj); - tobj->setTuioGeometry(tgeo); - } tgeo->setOuterContour(pointList);*/ - - } else if( strcmp( msg.AddressPattern(), "/tuio2/icg" ) == 0 ) { - if (lateFrame) return; - int32 s_id_raw; - args >> s_id_raw; - unsigned int s_id = (unsigned int)s_id_raw; - - std::list pointList; - while(!args.Eos()) { - float xpos,ypos; - args >> xpos >> ypos; - pointList.push_back(TuioPoint(frameTime, xpos, ypos)); - } - - TuioObject *tobj = getFrameObject(frameSource->getSourceID(),s_id); - if (tobj == NULL) tobj = new TuioObject(frameTime,frameSource,s_id); - addFrameObject(tobj); - - /*TuioGeometry *tgeo = tobj->getTuioGeometry(); - if (tgeo == NULL) { - tgeo = new TuioGeometry(frameTime, tobj); - tobj->setTuioGeometry(tgeo); - } tgeo->setOuterContour(pointList);*/ - - } else if( strcmp( msg.AddressPattern(), "/tuio2/alv" ) == 0 ) { - - if (lateFrame) return; - int32 s_id; - aliveObjectList.clear(); - while(!args.Eos()) { - args >> s_id; - aliveObjectList.push_back((unsigned int)s_id); - } - - lockObjectList(); - //find the removed tobjs first - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - if ((*tobj)->getTuioSource()->getSourceID()!=frameSource->getSourceID()) continue; - std::list::iterator iter = find(aliveObjectList.begin(), aliveObjectList.end(), (*tobj)->getSessionID()); - if (iter == aliveObjectList.end()) { - (*tobj)->remove(frameTime); - addFrameObject(*tobj); - } - } - unlockObjectList(); - - for (std::list::iterator iter=frameObjectList.begin(); iter!=frameObjectList.end(); iter++) { - TuioObject *tobj = (*iter); - - switch (tobj->getTuioState()) { - case TUIO_REMOVED: - - for (std::list::iterator listener=listenerList.begin(); listener!=listenerList.end(); listener++) - (*listener)->tuioRemove(tobj); - - lockObjectList(); - for (std::list::iterator delcon=tobjList.begin(); delcon!=tobjList.end(); delcon++) { - if (((*delcon)->getSessionID()==tobj->getSessionID()) && ((*delcon)->getTuioSource()->getSourceID()==frameSource->getSourceID())) { - delete *delcon; - tobjList.erase(delcon); - break; - } - } - unlockObjectList(); - break; - case TUIO_ADDED: - - lockObjectList(); - tobjList.push_back(tobj); - unlockObjectList(); - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioAdd(tobj); - - break; - default: - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioUpdate(tobj); - } - } - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioRefresh(frameTime); - - frameObjectList.clear(); - //unlockFrame(); - } - } catch( Exception& e ){ - std::cerr << "error parsing TUIO2 message: "<< msg.AddressPattern() << " - " << e.what() << std::endl; - //unlockFrame(); - } -} - -bool TuioClient::isConnected() { - return receiver->isConnected(); -} - -void TuioClient::connect(bool lock) { - - receiver->connect(lock); - unlockObjectList(); -} - -void TuioClient::disconnect() { - - receiver->disconnect(); - aliveObjectList.clear(); - - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) - delete (*iter); - tobjList.clear(); -} - -TuioObject* TuioClient::getTuioObject(unsigned int src_id, unsigned int s_id) { - lockObjectList(); - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { - unlockObjectList(); - return (*iter); - } - } - unlockObjectList(); - return NULL; -} - -TuioToken* TuioClient::getTuioToken(unsigned int src_id, unsigned int s_id) { - lockObjectList(); - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { - unlockObjectList(); - return (*iter)->getTuioToken(); - } - } - unlockObjectList(); - return NULL; -} - -TuioPointer* TuioClient::getTuioPointer(unsigned int src_id, unsigned int s_id) { - lockObjectList(); - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { - unlockObjectList(); - return (*iter)->getTuioPointer(); - } - } - unlockObjectList(); - return NULL; -} - -TuioBounds* TuioClient::getTuioBounds(unsigned int src_id, unsigned int s_id) { - lockObjectList(); - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { - unlockObjectList(); - return (*iter)->getTuioBounds(); - } - } - unlockObjectList(); - return NULL; -} - -TuioSymbol* TuioClient::getTuioSymbol(unsigned int src_id, unsigned int s_id) { - lockObjectList(); - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - if (((*iter)->getSessionID()==s_id) && ((*iter)->getTuioSource()->getSourceID()==src_id)) { - unlockObjectList(); - return (*iter)->getTuioSymbol(); - } - } - unlockObjectList(); - return NULL; -} - -std::list TuioClient::getTuioObjectList(unsigned int src_id) { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { - if ((*tobj)->getTuioSource()->getSourceID()==src_id) listBuffer.push_back(*tobj); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioClient::getTuioTokenList(unsigned int src_id) { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { - if ((*tobj)->getTuioSource()->getSourceID()==src_id) { - TuioToken *ttok = (*tobj)->getTuioToken(); - if (ttok!=NULL) listBuffer.push_back(ttok); - } - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioClient::getTuioPointerList(unsigned int src_id) { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { - if ((*tobj)->getTuioSource()->getSourceID()==src_id) { - TuioPointer *tptr = (*tobj)->getTuioPointer(); - if (tptr!=NULL) listBuffer.push_back(tptr); - } - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioClient::getTuioBoundsList(unsigned int src_id) { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { - if ((*tobj)->getTuioSource()->getSourceID()==src_id) { - TuioBounds *tbnd = (*tobj)->getTuioBounds(); - if (tbnd!=NULL) listBuffer.push_back(tbnd); - } - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioClient::getTuioSymbolList(unsigned int src_id) { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { - if ((*tobj)->getTuioSource()->getSourceID()==src_id) { - TuioSymbol *tsym = (*tobj)->getTuioSymbol(); - if (tsym!=NULL) listBuffer.push_back(tsym); - } - } - unlockObjectList(); - return listBuffer; -} - -void TuioClient::addFrameObject(TuioObject *tobj) { - for (std::list::iterator iter=frameObjectList.begin(); iter != frameObjectList.end(); iter++) { - if ((*iter)->getSessionID()==tobj->getSessionID()) return; - } - - frameObjectList.push_back(tobj); -} - -TuioObject* TuioClient::getFrameObject(unsigned int src_id, unsigned int s_id) { - for (std::list::iterator tobj=frameObjectList.begin(); tobj != frameObjectList.end(); tobj++) { - if ((*tobj)->getSessionID()==s_id) return *tobj; - } - - for (std::list::iterator tobj=tobjList.begin(); tobj != tobjList.end(); tobj++) { - if (((*tobj)->getSessionID()==s_id) && ((*tobj)->getTuioSource()->getSourceID()==src_id)) return *tobj; - } - - return NULL; -} - -void TuioClient::lockFrame() { -#ifndef WIN32 - pthread_mutex_lock(&frameMutex); -#else - WaitForSingleObject(frameMutex, INFINITE); -#endif -} - -void TuioClient::unlockFrame() { -#ifndef WIN32 - pthread_mutex_unlock(&frameMutex); -#else - ReleaseMutex(frameMutex); -#endif -} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioClient.h b/modules/touch/ext/libTUIO2/TUIO2/TuioClient.h deleted file mode 100644 index 65582f5f67..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioClient.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOCLIENT_H -#define INCLUDED_TUIOCLIENT_H - -#include "TuioDispatcher.h" -#include "OscReceiver.h" -#include "oscpack/osc/OscReceivedElements.h" - -#include -#include -#include -#include -#include -#include - -namespace TUIO2 { - - class OscReceiver; // Forward declaration - - /** - *

The TuioClient class is the central TUIO protocol decoder component. It provides a simple callback infrastructure using the {@link TuioListener} interface. - * In order to receive and decode TUIO messages an instance of TuioClient needs to be created. The TuioClient instance then generates TUIO events - * which are broadcasted to all registered classes that implement the {@link TuioListener} interface.

- *

- * TuioClient *client = new TuioClient();
- * client->addTuioListener(myTuioListener);
- * client->connect();
- *

- * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - class LIBDECL TuioClient : public TuioDispatcher { - - public: - /** - * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the default UDP port 3333 - * - */ - TuioClient(); - - /** - * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the provided UDP port - * - * @param port the UDP port the internal UdpReceiver is listening to - */ - TuioClient(unsigned short port); - - /** - * This constructor creates a TuioClient that uses the provided OscReceiver for the incoming OSC data - * - * @param oscreceiver the OscReceiver implementation for the chosen transport method (UDP, TCP ...) - */ - TuioClient(OscReceiver *oscreceiver); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioClient(); - - /** - * The TuioClient connects and starts receiving TUIO messages from its associated OscReceiver - * - * @param lock running in the background if set to false (default) - */ - void connect(bool lock=false); - - /** - * The TuioClient disconnects and stops receiving TUIO messages from its associated OscReceiver - */ - void disconnect(); - - /** - * Returns true if this TuioClient is currently connected. - * @return true if this TuioClient is currently connected - */ - bool isConnected(); - - /** - * Returns the TuioObject corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioObject - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioObject - * @return an active TuioObject corresponding to the provided Session ID or NULL - */ - using TuioDispatcher::getTuioObject; - TuioObject* getTuioObject(unsigned int src_id, unsigned int s_id); - - /** - * Returns a list of all currently active TuioObject - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a list of TuioObject - */ - using TuioDispatcher::getTuioObjectList; - std::list getTuioObjectList(unsigned int src_id); - - /** - * Returns the TuioToken corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioToken - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioToken - * @return an active TuioToken corresponding to the provided Session ID or NULL - */ - using TuioDispatcher::getTuioToken; - TuioToken* getTuioToken(unsigned int src_id, unsigned int s_id); - - /** - * Returns a list of all currently active TuioTokens - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a list of TuioTokens - */ - using TuioDispatcher::getTuioTokenList; - std::list getTuioTokenList(unsigned int src_id); - - /** - * Returns the TuioPointer corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioPointer - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioPointer - * @return an active TuioPointer corresponding to the provided Session ID or NULL - */ - using TuioDispatcher::getTuioPointer; - TuioPointer* getTuioPointer(unsigned int src_id, unsigned int s_id); - - /** - * Returns a List of all currently active TuioPointers - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioPointers - */ - using TuioDispatcher::getTuioPointerList; - std::list getTuioPointerList(unsigned int src_id); - - /** - * Returns the TuioBounds corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioBounds - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioBounds - * @return an active TuioBounds corresponding to the provided Session ID or NULL - */ - using TuioDispatcher::getTuioBounds; - TuioBounds* getTuioBounds(unsigned int src_id, unsigned int s_id); - - /** - * Returns a List of all currently active TuioBounds - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioBounds - */ - using TuioDispatcher::getTuioBoundsList; - std::list getTuioBoundsList(unsigned int src_id); - - /** - * Returns the TuioSymbol corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioSymbol - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioSymbol - * @return an active TuioSymbol corresponding to the provided Session ID or NULL - */ - using TuioDispatcher::getTuioSymbol; - TuioSymbol* getTuioSymbol(unsigned int src_id, unsigned int s_id); - - /** - * Returns a List of all currently active TuioSymbol - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioSymbol - */ - using TuioDispatcher::getTuioSymbolList; - std::list getTuioSymbolList(unsigned int src_id); - - /** - * Parses the incoming OSC message - * - * @param message the incoming OSC message - */ - void processOSC( const osc::ReceivedMessage& message); - - private: - void initialize(); - - void addFrameObject(TuioObject *con); - TuioObject* getFrameObject(unsigned int src_id,unsigned int s_id); - std::list aliveObjectList; - std::list frameObjectList; - - TuioTime frameTime; - bool lateFrame; - - unsigned int source_count; - std::map sourceList; - TuioSource *frameSource; - - OscReceiver *receiver; - bool local_receiver; - -#ifndef WIN32 - pthread_mutex_t frameMutex; -#else - HANDLE frameMutex; -#endif - - void lockFrame(); - void unlockFrame(); - }; -}; -#endif /* INCLUDED_TUIOCLIENT_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp deleted file mode 100644 index d27a3dad28..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioComponent.h" -#include "TuioObject.h" -using namespace TUIO2; - -TuioComponent::TuioComponent (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a):TuioPoint(ttime, xp,yp) -,state(TUIO_ADDED) -{ - container = tobj; - angle = a; - x_speed = 0.0f; - y_speed = 0.0f; - motion_speed = 0.0f; - motion_accel = 0.0f; - rotation_speed = 0.0f; - rotation_accel = 0.0f; - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - } - -TuioComponent::TuioComponent (TuioObject *tobj, float xp, float yp, float a):TuioPoint(xp,yp) -,state(TUIO_ADDED) -{ - container = tobj; - angle = a; - x_speed = 0.0f; - y_speed = 0.0f; - motion_speed = 0.0f; - motion_accel = 0.0f; - rotation_speed = 0.0f; - rotation_accel = 0.0f; - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); -} - -TuioComponent::TuioComponent (TuioComponent *tcomp):TuioPoint(tcomp) -,state(TUIO_ADDED) -{ - container = tcomp->getContainingTuioObject(); - angle = tcomp->getAngle(); - x_speed = 0.0f; - y_speed = 0.0f; - motion_speed = 0.0f; - motion_accel = 0.0f; - rotation_speed = 0.0f; - rotation_accel = 0.0f; - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); -} - -TuioObject* TuioComponent::getContainingTuioObject() { - return container; -} - -void TuioComponent::setContainingTuioObject(TuioObject *tobj) { - container = tobj; -} - -void TuioComponent::update (TuioTime ttime, float xp, float yp, float a) { - TuioPoint lastPoint = path.back(); - TuioPoint::update(ttime,xp, yp); - - TuioTime diffTime = currentTime - lastPoint.getTuioTime(); - float dt = diffTime.getTotalMilliseconds()/1000.0f; - float dx = xpos - lastPoint.getX(); - float dy = ypos - lastPoint.getY(); - float dist = sqrt(dx*dx+dy*dy); - float last_motion_speed = motion_speed; - - x_speed = dx/dt; - y_speed = dy/dt; - motion_speed = dist/dt; - motion_accel = (motion_speed - last_motion_speed)/dt; - - float last_angle = angle; - float last_rotation_speed = rotation_speed; - angle = a; - - double da = (angle-last_angle)/(2*M_PI); - if (da > 0.75f) da-=1.0f; - else if (da < -0.75f) da+=1.0f; - - rotation_speed = (float)da/dt; - rotation_accel = (rotation_speed - last_rotation_speed)/dt; - - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; - else state = TUIO_STOPPED; - - container->update(ttime); -} - -void TuioComponent::stop(TuioTime ttime) { - update(ttime,xpos,ypos); - container->update(ttime); -} - -void TuioComponent::update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { - TuioPoint::update(ttime,xp, yp); - angle = a; - x_speed = xs; - y_speed = ys; - motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); - rotation_speed = rs; - motion_accel = ma; - rotation_accel = ra; - - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; - else state = TUIO_STOPPED; - - container->update(ttime); - } - -void TuioComponent::update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { - TuioPoint::update(xp,yp); - angle = a; - x_speed = xs; - y_speed = ys; - motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); - rotation_speed = rs; - motion_accel = ma; - rotation_accel = ra; - - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; - else state = TUIO_STOPPED; - - container->update(currentTime); -} - -void TuioComponent::update (TuioComponent *tcomp) { - TuioPoint::update(tcomp); - angle = tcomp->getAngle(); - x_speed = tcomp->getXSpeed(); - y_speed = tcomp->getYSpeed(); - motion_speed = tcomp->getMotionSpeed(); - rotation_speed = tcomp->getRotationSpeed(); - motion_accel = tcomp->getMotionAccel(); - rotation_accel = tcomp->getRotationAccel(); - - TuioPoint p(tcomp->getTuioTime(),xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; - else state = TUIO_STOPPED; - - container->update(tcomp->getTuioTime()); -} - -void TuioComponent::remove(TuioTime ttime) { - currentTime = ttime; - state = TUIO_REMOVED; - container->update(ttime); -} - -unsigned int TuioComponent::getSessionID() const{ - return container->getSessionID(); -} - -float TuioComponent::getAngle() const{ - return angle; -} - -float TuioComponent::getAngleDegrees() const{ - return (float)(angle/M_PI*180); -} - -float TuioComponent::getXSpeed() const{ - return x_speed; -} - -float TuioComponent::getYSpeed() const{ - return y_speed; -} - -TuioPoint TuioComponent::getPosition() const{ - TuioPoint p(xpos,ypos); - return p; -} - -std::list TuioComponent::getPath() const{ - return path; -} - -float TuioComponent::getMotionSpeed() const{ - return motion_speed; -} - -float TuioComponent::getMotionAccel() const{ - return motion_accel; -} - -float TuioComponent::getRotationSpeed() const{ - return rotation_speed; -} - -float TuioComponent::getRotationAccel() const{ - return rotation_accel; -} - -int TuioComponent::getTuioState() const{ - return state; -} - -bool TuioComponent::isMoving() const{ - if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true; - else return false; -} - diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h b/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h deleted file mode 100644 index d7790efe8a..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioComponent.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOCOMPONENT_H -#define INCLUDED_TUIOCOMPONENT_H - -#include "TuioPoint.h" -#include -#include - -#define TUIO_IDLE 0 -#define TUIO_ADDED 1 -#define TUIO_ACCELERATING 2 -#define TUIO_DECELERATING 3 -#define TUIO_ROTATING 4 -#define TUIO_STOPPED 5 -#define TUIO_REMOVED 6 - -#define MAX_PATH_SIZE 128 - -namespace TUIO2 { - - /** - * The abstract TuioComponent class defines common attributes that apply to all subclasses {@link TuioToken}, {@link TuioPointer} and {@link TuioBounds}. - * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - - class TuioObject; - class LIBDECL TuioComponent: public TuioPoint { - - protected: - /** - * The TuioObject that contains this TUIO component. - */ - TuioObject *container; - /** - * The rotation angle value. - */ - float angle; - /** - * The X-axis velocity value. - */ - float x_speed; - /** - * The Y-axis velocity value. - */ - float y_speed; - /** - * The motion speed value. - */ - float motion_speed; - /** - * The motion acceleration value. - */ - float motion_accel; - /** - * The rotation speed value. - */ - float rotation_speed; - /** - * The rotation acceleration value. - */ - float rotation_accel; - /** - * A List of TuioPoints containing all the previous positions of the TUIO component. - */ - std::list path; - /** - * Reflects the current state of the TuioComponent - */ - int state; - - public: - using TuioPoint::update; - - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, X and Y coordinate to the newly created TuioComponent. - * - * @param ttime the TuioTime to assign - * @param tobj the TuioObject to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - TuioComponent (TuioTime ttime, TuioObject *tobj, float xp, float yp, float a); - - /** - * This constructor takes the provided Session ID, X and Y coordinate - * and assigs these values to the newly created TuioComponent. - * - * @param tobj the TuioObject to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - TuioComponent (TuioObject *tobj, float xp, float yp,float a); - - /** - * This constructor takes the atttibutes of the provided TuioComponent - * and assigs these values to the newly created TuioComponent. - * - * @param tcon the TuioComponent to assign - */ - TuioComponent (TuioComponent *tcon); - - /** - * The destructor is doing nothing in particular. - */ - virtual ~TuioComponent(){}; - - /** - * Returns the TuioObject containing this TuioComponent. - * @return the TuioObject containing this TuioComponent - */ - virtual TuioObject* getContainingTuioObject(); - - /** - * Returns the TuioObject containing this TuioComponent. - * @param the TuioObject containing this TuioComponent - */ - virtual void setContainingTuioObject(TuioObject *tobj); - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate to the private TuioComponent attributes. - * The speed and accleration values are calculated accordingly. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - virtual void update (TuioTime ttime, float xp, float yp, float a); - - /** - * This method is used to calculate the speed and acceleration values of - * TuioComponents with unchanged positions. - */ - virtual void stop(TuioTime ttime); - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate, X and Y velocity and acceleration - * to the private TuioComponent attributes. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param rs the rotation velocity to assign - * @param ma the motion acceleration to assign - * @param ra the rotation acceleration to assign - */ - virtual void update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); - - /** - * Assigns the provided X and Y coordinate, X and Y velocity and acceleration - * to the private TuioComponent attributes. The TuioTime time stamp remains unchanged. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param rs the rotation velocity to assign - * @param ma the motion acceleration to assign - * @param ra the rotation acceleration to assign - */ - virtual void update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); - - /** - * Takes the atttibutes of the provided TuioComponent - * and assigs these values to this TuioComponent. - * The TuioTime time stamp of this TuioComponent remains unchanged. - * - * @param tcon the TuioComponent to assign - */ - virtual void update(TuioComponent *tcon); - - /** - * Assigns the REMOVE state to this TuioComponent and sets - * its TuioTime time stamp to the provided TuioTime argument. - * - * @param ttime the TuioTime to assign - */ - virtual void remove(TuioTime ttime); - - /** - * Returns the Session ID of this TuioComponent. - * @return the Session ID of this TuioComponent - */ - virtual unsigned int getSessionID() const; - - /** - * Returns the X velocity of this TuioComponent. - * @return the X velocity of this TuioComponent - */ - virtual float getXSpeed() const; - - /** - * Returns the Y velocity of this TuioComponent. - * @return the Y velocity of this TuioComponent - */ - virtual float getYSpeed() const; - - /** - * Returns the position of this TuioComponent. - * @return the position of this TuioComponent - */ - virtual TuioPoint getPosition() const; - - /** - * Returns the path of this TuioComponent. - * @return the path of this TuioComponent - */ - virtual std::list getPath() const; - - /** - * Returns the motion speed of this TuioComponent. - * @return the motion speed of this TuioComponent - */ - virtual float getMotionSpeed() const; - - /** - * Returns the motion acceleration of this TuioComponent. - * @return the motion acceleration of this TuioComponent - */ - virtual float getMotionAccel() const; - - /** - * Returns the rotation angle of this TuioComponent. - * @return the rotation angle of this TuioComponent - */ - float getAngle() const; - - /** - * Returns the rotation angle in degrees of this TuioComponent. - * @return the rotation angle in degrees of this TuioComponent - */ - float getAngleDegrees() const; - - /** - * Returns the rotation speed of this TuioComponent. - * @return the rotation speed of this TuioComponent - */ - float getRotationSpeed() const; - - /** - * Returns the rotation acceleration of this TuioComponent. - * @return the rotation acceleration of this TuioComponent - */ - float getRotationAccel() const; - - /** - * Returns the TUIO state of this TuioComponent. - * @return the TUIO state of this TuioComponent - */ - virtual int getTuioState() const; - - /** - * Returns true of this TuioComponent is moving. - * @return true of this TuioComponent is moving - */ - virtual bool isMoving() const; - }; -} -#endif // INCLUDED_TUIOCOMPONENT_H \ No newline at end of file diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp deleted file mode 100644 index d3ff480026..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioDispatcher.h" - -#include -#include -#include -#include - -using namespace TUIO2; - -TuioDispatcher::TuioDispatcher() { -#ifndef WIN32 - pthread_mutex_init(&tobjMutex,NULL); -#else - tobjMutex = CreateMutex(NULL,FALSE,"tobjMutex"); -#endif -} - -TuioDispatcher::~TuioDispatcher() { -#ifndef WIN32 - pthread_mutex_destroy(&tobjMutex); -#else - CloseHandle(tobjMutex); -#endif -} - -void TuioDispatcher::lockObjectList() { -#ifndef WIN32 - pthread_mutex_lock(&tobjMutex); -#else - WaitForSingleObject(tobjMutex, INFINITE); -#endif -} - -void TuioDispatcher::unlockObjectList() { -#ifndef WIN32 - pthread_mutex_unlock(&tobjMutex); -#else - ReleaseMutex(tobjMutex); -#endif -} - -void TuioDispatcher::addTuioListener(TuioListener *listener) { - listenerList.push_back(listener); -} - -void TuioDispatcher::removeTuioListener(TuioListener *listener) { - std::list::iterator result = find(listenerList.begin(),listenerList.end(),listener); - if (result!=listenerList.end()) listenerList.remove(listener); -} - -void TuioDispatcher::removeAllTuioListeners() { - listenerList.clear(); -} - -TuioObject* TuioDispatcher::getTuioObject(unsigned int s_id) { - lockObjectList(); - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - if((*tobj)->getSessionID()==s_id) { - unlockObjectList(); - return (*tobj); - } - } - unlockObjectList(); - return NULL; -} - -TuioToken* TuioDispatcher::getTuioToken(unsigned int s_id) { - TuioObject *tobj = getTuioObject(s_id); - if (tobj==NULL) return NULL; - - return tobj->getTuioToken(); -} - -TuioPointer* TuioDispatcher::getTuioPointer(unsigned int s_id) { - TuioObject *tobj = getTuioObject(s_id); - if (tobj==NULL) return NULL; - - return tobj->getTuioPointer(); -} - -TuioBounds* TuioDispatcher::getTuioBounds(unsigned int s_id) { - TuioObject *tobj = getTuioObject(s_id); - if (tobj==NULL) return NULL; - - return tobj->getTuioBounds(); -} - -TuioSymbol* TuioDispatcher::getTuioSymbol(unsigned int s_id) { - TuioObject *tobj = getTuioObject(s_id); - if (tobj==NULL) return NULL; - - return tobj->getTuioSymbol(); -} - -std::list TuioDispatcher::getTuioObjectList() { - std::list listBuffer; - lockObjectList(); - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - listBuffer.push_back(*tobj); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioDispatcher::getTuioTokenList() { - std::list listBuffer; - lockObjectList(); - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - TuioToken *ttok = (*tobj)->getTuioToken(); - if (ttok!=NULL) listBuffer.push_back(ttok); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioDispatcher::getTuioPointerList() { - std::list listBuffer; - lockObjectList(); - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - TuioPointer *tptr = (*tobj)->getTuioPointer(); - if (tptr!=NULL) listBuffer.push_back(tptr); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioDispatcher::getTuioBoundsList() { - std::list listBuffer; - lockObjectList(); - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - TuioBounds *tbnd = (*tobj)->getTuioBounds(); - if (tbnd!=NULL) listBuffer.push_back(tbnd); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioDispatcher::getTuioSymbolList() { - std::list listBuffer; - lockObjectList(); - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - TuioSymbol *tsym = (*tobj)->getTuioSymbol(); - if (tsym!=NULL) listBuffer.push_back(tsym); - } - unlockObjectList(); - return listBuffer; -} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h b/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h deleted file mode 100644 index 966975fea3..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioDispatcher.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIODISPATCHER_H -#define INCLUDED_TUIODISPATCHER_H - -#include "TuioListener.h" - -#ifndef WIN32 -#include -#else -#include -#endif - -namespace TUIO2 { - - /** - *

The TuioDispatcher generates TUIO events which are broadcasted to all - * registered classes that implement the {@link TuioListener} interface.

- * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - class LIBDECL TuioDispatcher { - - public: - /** - * This constructor creates a TuioDispatcher - * - */ - TuioDispatcher(); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioDispatcher(); - - /** - * Adds the provided TuioListener to the list of registered TUIO event listeners - * - * @param listener the TuioListener to add - */ - void addTuioListener(TuioListener *listener); - - /** - * Removes the provided TuioListener from the list of registered TUIO event listeners - * - * @param listener the TuioListener to remove - */ - void removeTuioListener(TuioListener *listener); - - /** - * Removes all TuioListener from the list of registered TUIO event listeners - */ - void removeAllTuioListeners(); - - /** - * Returns a List of all currently active TuioObject - * - * @return a List of all currently active TuioObject - */ - std::list getTuioObjectList(); - - /** - * Returns a List of all currently active TuioTokens - * - * @return a List of all currently active TuioTokens - */ - std::list getTuioTokenList(); - - /** - * Returns a List of all currently active TuioPointers - * - * @return a List of all currently active TuioPointers - */ - std::list getTuioPointerList(); - - /** - * Returns a List of all currently active TuioBounds - * - * @return a List of all currently active TuioBounds - */ - std::list getTuioBoundsList(); - - /** - * Returns a List of all currently active TuioSymbols - * - * @return a List of all currently active TuioSymbols - */ - std::list getTuioSymbolList(); - - /** - * Returns the TuioObject corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioObject - * - * @return an active TuioObject corresponding to the provided Session ID or NULL - */ - TuioObject* getTuioObject(unsigned int s_id); - - /** - * Returns the TuioToken corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioToken - * - * @return an active TuioToken corresponding to the provided Session ID or NULL - */ - TuioToken* getTuioToken(unsigned int s_id); - - /** - * Returns the TuioPointer corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioPointer - * - * @return an active TuioPointer corresponding to the provided Session ID or NULL - */ - TuioPointer* getTuioPointer(unsigned int s_id); - - /** - * Returns the TuioBounds corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioBounds - * - * @return an active TuioBounds corresponding to the provided Session ID or NULL - */ - TuioBounds* getTuioBounds(unsigned int s_id); - - /** - * Returns the TuioSymbol corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioSymbol - * - * @return an active TuioSymbol corresponding to the provided Session ID or NULL - */ - TuioSymbol* getTuioSymbol(unsigned int s_id); - - /** - * Locks the TuioObject list in order to avoid updates during access - */ - void lockObjectList(); - - /** - * Releases the lock of the TuioObject list - */ - void unlockObjectList(); - - protected: - std::list listenerList; - std::list tobjList; - -#ifndef WIN32 - pthread_mutex_t tobjMutex; -#else - HANDLE tobjMutex; -#endif - - }; -} -#endif /* INCLUDED_TUIODISPATCHER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioListener.h b/modules/touch/ext/libTUIO2/TUIO2/TuioListener.h deleted file mode 100644 index 160d756f33..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioListener.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOLISTENER_H -#define INCLUDED_TUIOLISTENER_H - -#include "TuioObject.h" - -namespace TUIO2 { - - /** - *

The TuioListener interface provides a simple callback infrastructure which is used by the {@link TuioClient} class - * to dispatch TUIO events to all registered instances of classes that implement the TuioListener interface defined here.

- *

Any class that implements the TuioListener interface is required to implement all of the callback methods defined here. - * The {@link TuioClient} makes use of these interface methods in order to dispatch TUIO events to all registered TuioListener implementations.

- *

- * public class MyTuioListener implements TuioListener
- * ...

- * MyTuioListener listener = new MyTuioListener();
- * TuioClient client = new TuioClient();
- * client.addTuioListener(listener);
- * client.start();
- *

- * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - class LIBDECL TuioListener { - - public: - /** - * The destructor is doing nothing in particular. - */ - virtual ~TuioListener(){}; - - /** - * This callback method is invoked by the TuioClient when a new TUIO Component is added to the session. - * - * @param tobj the TuioObject reference that encapsulates all related TUIO Components - */ - virtual void tuioAdd(TuioObject *tobj)=0; - - /** - * This callback method is invoked by the TuioClient when an existing TUIO Component is updated during the session. - * - * @param tobj the TuioObject reference that encapsulates all related TUIO Components - */ - virtual void tuioUpdate(TuioObject *tobj)=0; - - /** - * This callback method is invoked by the TuioClient when a TUIO Component is removed from the session. - * - * @param tobj the TuioObject reference that encapsulates all related TUIO Components - */ - virtual void tuioRemove(TuioObject *tobj)=0; - - /** - * This callback method is invoked by the TuioClient to mark the end of a received TUIO message bundle. - * - * @param ftime the TuioTime associated to the current TUIO message bundle - */ - virtual void tuioRefresh(TuioTime ftime)=0; - }; -} -#endif /* INCLUDED_TUIOLISTENER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp deleted file mode 100644 index 070c8f39ba..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioManager.cpp +++ /dev/null @@ -1,575 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioManager.h" -using namespace TUIO2; - -TuioManager::TuioManager() - : currentFrameTime(TuioTime::getSystemTime()) - , currentFrame(-1) - , pointerCount(0) - , maxPointerID(-1) - , sessionID(-1) - , tobjUpdate(false) - , verbose(false) - , invert_x(false) - , invert_y(false) - , invert_a(false) -{ - -} - -TuioManager::~TuioManager() { -} - -TuioObject* TuioManager::createTuioObject() { - sessionID++; - TuioObject *tobj = new TuioObject(sessionID); - tobjList.push_back(tobj); - return tobj; -} - -void TuioManager::addExternalTuioObject(TuioObject *tobj) { - if (tobj==NULL) return; - tobjList.push_back(tobj); - - TuioPointer *tptr = tobj->getTuioPointer(); - if (tptr!=NULL) pointerCount++; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioAdd(tobj); - - if (verbose) std::cout << "add " << tobj->getSessionID() << std::endl; - tobjUpdate = true; -} - -void TuioManager::updateExternalTuioObject(TuioObject *tobj) { - if (tobj==NULL) return; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioUpdate(tobj); - - if (verbose) std::cout << "set " << tobj->getSessionID() << std::endl; - tobjUpdate = true; -} - -void TuioManager::removeExternalTuioObject(TuioObject *tobj) { - if (tobj==NULL) return; - tobjList.remove(tobj); - - TuioPointer *tptr = tobj->getTuioPointer(); - if (tptr!=NULL) pointerCount--; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioRemove(tobj); - - if (verbose) std::cout << "del " << tobj->getSessionID() << std::endl; - tobjUpdate = true; -} - -void TuioManager::removeTuioObject(unsigned int s_id) { - - TuioObject *tobj = NULL; - for(std::list::iterator iter = tobjList.begin();iter!= tobjList.end(); iter++) { - if((*iter)->getSessionID()==s_id) { - tobj = *iter; - break; - } - } - if (tobj==NULL) return; - else removeTuioObject(tobj); -} - -void TuioManager::removeTuioObject(TuioObject *tobj) { - - if (tobj== NULL) return; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioRemove(tobj); - - if (tobj->containsTuioToken()) { - if (verbose) std::cout << "del tok " << tobj->getSessionID() << std::endl; - tobj->deleteTuioToken(); - } - - if (tobj->containsTuioPointer()) { - if (verbose) std::cout << "del ptr " << tobj->getSessionID() << std::endl; - tobj->deleteTuioPointer(); - } - - if (tobj->containsTuioBounds()) { - if (verbose) std::cout << "del bnd " << tobj->getSessionID() << std::endl; - tobj->deleteTuioBounds(); - } - - if (tobj->containsTuioSymbol()) { - if (verbose) std::cout << "del sym " << tobj->getSessionID() << std::endl; - tobj->deleteTuioSymbol(); - } - - tobjList.remove(tobj); - tobjUpdate = true; - delete tobj; -} - -TuioObject* TuioManager::createTuioToken(unsigned int sym, float x, float y, float a) { - return addTuioToken(NULL, sym, 0, 0, x, y, a); -} - -TuioObject* TuioManager::createTuioToken(unsigned int sym, unsigned short t_id, unsigned short u_id, float x, float y, float a) { - return addTuioToken(NULL, sym, t_id, u_id, x, y, a); -} - -TuioObject* TuioManager::addTuioToken(TuioObject *tobj, unsigned int sym, float x, float y, float a) { - return addTuioToken(tobj, sym, 0, 0, x, y, a); -} - -TuioObject* TuioManager::addTuioToken(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, float x, float y, float a) { - - TuioToken *ttok = new TuioToken(currentFrameTime, tobj, t_id, u_id, sym, x, y, a); - return addTuioToken(ttok); -} - -TuioObject* TuioManager::addTuioToken(TuioToken *ttok) { - if (ttok==NULL) return NULL; - - TuioObject *tobj = ttok->getContainingTuioObject(); - if (tobj==NULL) tobj = createTuioObject(); - tobj->setTuioToken(ttok); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { - (*listener)->tuioAdd(tobj); - } - - if (verbose) std::cout << "add tok " << tobj->getSessionID() << std::endl; - tobjUpdate = true; - - return tobj; -} - -void TuioManager::updateTuioToken(TuioToken *ttok, float x, float y, float a) { - if (ttok==NULL) return; - if (ttok->getTuioTime()==currentFrameTime) return; - - ttok->update(currentFrameTime,x,y,a); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioUpdate(ttok->getContainingTuioObject()); - - if (verbose)std::cout << "set tok " << ttok->getSessionID() << std::endl; - tobjUpdate = true; -} - -void TuioManager::removeTuioToken(TuioToken *ttok) { - if (ttok==NULL) return; - - TuioObject *tobj = ttok->getContainingTuioObject(); - if (tobj==NULL) { - delete ttok; - return; - } else removeTuioObject(tobj); -} - -TuioObject* TuioManager::createTuioPointer(float x, float y, float a, float s, float r, float p) { - return addTuioPointer(NULL, 0, 0, x, y, a, s, r, p); -} - -TuioObject* TuioManager::createTuioPointer(unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { - return addTuioPointer(NULL, t_id, u_id, x, y, a, s, r, p); -} - -TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, float x, float y, float a, float s, float r, float p) { - return addTuioPointer(tobj, 0, 0, x, y, a, s, r, p); -} - -TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { - - int pointerID = pointerCount; - if ((pointerCount<=maxPointerID) && (freePointerList.size()>0)) { - std::list::iterator closestPointer = freePointerList.begin(); - - for(std::list::iterator iter = freePointerList.begin();iter!= freePointerList.end(); iter++) { - if((*iter)->getDistance(x,y)<(*closestPointer)->getDistance(x,y)) closestPointer = iter; - } - - TuioPointer *freePointer = (*closestPointer); - pointerID = (*closestPointer)->getPointerID(); - freePointerList.erase(closestPointer); - delete freePointer; - } else maxPointerID = pointerID; - - TuioPointer *tptr = new TuioPointer(currentFrameTime, tobj, t_id, u_id, pointerID, x, y, a, s, r, p); - return addTuioPointer(tptr); -} - -TuioObject* TuioManager::createTuioPointer(unsigned int p_id, float x, float y, float a, float s, float r, float p) { - - return addTuioPointer(NULL, p_id, 0, 0, x, y, a, s, r, p); -} - -TuioObject* TuioManager::createTuioPointer(unsigned int p_id, unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { - - return addTuioPointer(NULL, p_id, t_id, u_id, x, y, a, s, r, p); -} - -TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, unsigned int p_id, float x, float y, float a, float s, float r, float p) { - - return addTuioPointer(tobj, p_id, 0, 0, x, y, a, s, r, p); -} - -TuioObject* TuioManager::addTuioPointer(TuioObject *tobj, unsigned int p_id, unsigned short t_id, unsigned short u_id, float x, float y, float a, float s, float r, float p) { - - TuioPointer *tptr = new TuioPointer(currentFrameTime, tobj, t_id, u_id, p_id, x, y, a, s, r, p); - return addTuioPointer(tptr); -} - -TuioObject* TuioManager::addTuioPointer(TuioPointer *tptr) { - if (tptr==NULL) return NULL; - - TuioObject *tobj = tptr->getContainingTuioObject(); - - if (tobj==NULL) tobj = createTuioObject(); - tobj->setTuioPointer(tptr); - pointerCount++; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { - (*listener)->tuioAdd(tobj); - } - - if (verbose) std::cout << "add ptr " << tobj->getSessionID() << std::endl; - tobjUpdate = true; - - return tobj; -} - -void TuioManager::updateTuioPointer(TuioPointer *tptr, float x, float y, float a, float s, float r, float p) { - if (tptr==NULL) return; - if (tptr->getTuioTime()==currentFrameTime) return; - - TuioObject *tobj = tptr->getContainingTuioObject(); - if (tobj==NULL) return; - - tptr->update(currentFrameTime,x,y,a,s,r,p); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioUpdate(tobj); - - if (verbose)std::cout << "set ptr " << tobj->getSessionID() << std::endl; - tobjUpdate = true; -} - -void TuioManager::removeTuioPointer(TuioPointer *tptr) { - if (tptr==NULL) return; - pointerCount--; - - TuioObject *tobj = tptr->getContainingTuioObject(); - - if (tptr->getPointerID()==maxPointerID) { - maxPointerID = -1; - - if (pointerCount>0) { - - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - if ((*iter)->containsTuioPointer()) { - int pointerID = (*iter)->getTuioPointer()->getPointerID(); - if (pointerID>maxPointerID) maxPointerID=pointerID; - } - } - - freePointerBuffer.clear(); - for (std::list::iterator flist=freePointerList.begin(); flist != freePointerList.end(); flist++) { - TuioPointer *freePointer = (*flist); - if (freePointer->getPointerID()<=maxPointerID) freePointerBuffer.push_back(new TuioPointer(freePointer)); - } - - freePointerList = freePointerBuffer; - - } else { - for (std::list::iterator flist=freePointerList.begin(); flist != freePointerList.end(); flist++) { - TuioPointer *freePointer = (*flist); - delete freePointer; - } - freePointerList.clear(); - } - } else if (tptr->getPointerID()getContainingTuioObject(); - - if (tobj==NULL) tobj = createTuioObject(); - tobj->setTuioBounds(tbnd); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { - (*listener)->tuioAdd(tobj); - } - - if (verbose) std::cout << "add bnd " << tobj->getSessionID() << std::endl; - tobjUpdate = true; - - return tobj; -} - -void TuioManager::updateTuioBounds(TuioBounds *tbnd, float x, float y, float a, float w, float h, float f) { - if (tbnd==NULL) return; - if (tbnd->getTuioTime()==currentFrameTime) return; - - tbnd->update(currentFrameTime,x,y,a,w,h,f); - TuioObject *tobj = tbnd->getContainingTuioObject(); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioUpdate(tobj); - - if (verbose)std::cout << "set bnd " << tobj->getSessionID() << std::endl; - tobjUpdate = true; -} - -void TuioManager::removeTuioBounds(TuioBounds *tbnd) { - if (tbnd==NULL) return; - - TuioObject *tobj = tbnd->getContainingTuioObject(); - if (tobj==NULL) { - delete tbnd; - return; - } else removeTuioObject(tobj); -} - -TuioObject* TuioManager::createTuioSymbol(unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data) { - - return addTuioSymbol(NULL, t_id, u_id, sym, type, data); -} - -TuioObject* TuioManager::addTuioSymbol(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data) { - - TuioSymbol *tsym = new TuioSymbol(currentFrameTime, tobj, t_id, u_id, sym, type, data); - return addTuioSymbol(tsym); -} - -TuioObject* TuioManager::addTuioSymbol(TuioSymbol *tsym) { - if (tsym==NULL) return NULL; - - TuioObject *tobj = tsym->getContainingTuioObject(); - if (tobj==NULL) tobj = createTuioObject(); - tobj->setTuioSymbol(tsym); - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) { - if (tobjUpdate)(*listener)->tuioUpdate(tobj); - else(*listener)->tuioAdd(tobj); - } - - if (verbose) std::cout << "add sym " << tobj->getSessionID() << std::endl; - tobjUpdate = true; - - return tobj; -} - -void TuioManager::removeTuioSymbol(TuioSymbol *tsym) { - if (tsym==NULL) return; - - TuioObject *tobj = tsym->getContainingTuioObject(); - if (tobj==NULL) { - delete tsym; - return; - } else removeTuioObject(tobj); -} - -int TuioManager::getSessionID() { - sessionID++; - if (sessionID==UINT_MAX) sessionID = 0; - return sessionID; -} - -int TuioManager::getFrameID() { - return currentFrame; -} - -TuioTime TuioManager::getFrameTime() { - return currentFrameTime; -} - -void TuioManager::initTuioFrame(TuioTime ttime) { - frameTimeTag = TuioTime::getSystemTimeTag(); - currentFrameTime = TuioTime(ttime); - currentFrame++; - if (currentFrame==UINT_MAX) currentFrame = 1; -} - -void TuioManager::commitTuioFrame() { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->tuioRefresh(currentFrameTime); - - if (verbose) std::cout << "refresh " << currentFrame << " " << currentFrameTime.getTotalMilliseconds() << std::endl; -} - -TuioToken* TuioManager::getClosestTuioToken(float xp, float yp) { - - TuioToken *closestToken = NULL; - float closestDistance = 1.0f; - - for (std::list::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - TuioToken *ttok = (*iter)->getTuioToken(); - if (ttok==NULL) continue; - float distance = ttok->getDistance(xp,yp); - if(distance::iterator iter=tobjList.begin(); iter != tobjList.end(); iter++) { - TuioPointer *tptr = (*iter)->getTuioPointer(); - if (tptr==NULL) continue; - float distance = tptr->getDistance(xp,yp); - if(distance::iterator iter=tobjList.begin(); iter!=tobjList.end(); iter++) { - TuioBounds *tbnd = (*iter)->getTuioBounds(); - if (tbnd==NULL) continue; - float distance = tbnd->getDistance(xp,yp); - if(distance TuioManager::getUntouchedObjects() { - - std::list untouched; - for (std::list::iterator tobj=tobjList.begin(); tobj!=tobjList.end(); tobj++) { - - bool touched = false; - if ((*tobj)->containsTuioToken()) { - if ((*tobj)->getTuioToken()->getTuioTime()==currentFrameTime) touched=true; - } - - if ((*tobj)->containsTuioPointer()) { - if ((*tobj)->getTuioPointer()->getTuioTime()==currentFrameTime) touched=true; - } - - if ((*tobj)->containsTuioBounds()) { - if ((*tobj)->getTuioToken()->getTuioTime()==currentFrameTime) touched=true; - } - - if ((*tobj)->containsTuioSymbol()) { - if ((*tobj)->getTuioSymbol()->getTuioTime()==currentFrameTime) touched=true; - } - - if (!touched) untouched.push_back(*tobj); - - } - return untouched; -} - -void TuioManager::stopUntouchedMovingObjects() { - - for (std::list::iterator tobj = tobjList.begin(); tobj!=tobjList.end(); tobj++) { - - if ((*tobj)->containsTuioToken()) { - TuioToken *ttok = (*tobj)->getTuioToken(); - if ((ttok->getTuioTime()!=currentFrameTime) && (ttok->isMoving())) { - ttok->stop(currentFrameTime); - if (verbose) std::cout << "set tok " << ttok->getSessionID() << std::endl; - tobjUpdate = true; - } - } - - if ((*tobj)->containsTuioPointer()) { - TuioPointer *tptr = (*tobj)->getTuioPointer(); - if ((tptr->getTuioTime()!=currentFrameTime) && (tptr->isMoving())) { - tptr->stop(currentFrameTime); - if (verbose) std::cout << "set ptr " << tptr->getSessionID() << std::endl; - tobjUpdate = true; - } - } - - if ((*tobj)->containsTuioBounds()) { - TuioBounds *tbnd = (*tobj)->getTuioBounds(); - if ((tbnd->getTuioTime()!=currentFrameTime) && (tbnd->isMoving())) { - tbnd->stop(currentFrameTime); - if (verbose) std::cout << "set bnd " << tbnd->getSessionID() << std::endl; - tobjUpdate = true; - } - } - - } -} - -void TuioManager::removeUntouchedStoppedObjects() { - std::list::iterator iter = tobjList.begin(); - while (iter!=tobjList.end()) { - TuioObject *tobj = (*iter); - if ((tobj->getTuioTime()!=currentFrameTime) && (!tobj->isMoving())) { - removeTuioObject(tobj); - iter = tobjList.begin(); - } else iter++; - } -} - -void TuioManager::resetTuioObjectList() { - - pointerCount=0; - std::list::iterator tobj = tobjList.begin(); - while (tobj!=tobjList.end()) { - removeTuioObject((*tobj)); - tobj = tobjList.begin(); - } -} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioManager.h b/modules/touch/ext/libTUIO2/TUIO2/TuioManager.h deleted file mode 100644 index fac3d55327..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioManager.h +++ /dev/null @@ -1,601 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOMANAGER_H -#define INCLUDED_TUIOMANAGER_H - -#include "TuioDispatcher.h" - -#include -#include -#include - -namespace TUIO2 { - /** - *

The TuioManager class is the central TUIO session management component.

- *

During runtime the each frame is marked with the initFrame and commitFrame methods, - * while the currently present TuioTokens are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

- *

- * TuioManager *manager = new TuioManager();
- * ...
- * server->initTuioFrame(TuioTime::getSessionTime());
- * TuioToken *ttok = server->addTuioToken(xpos,ypos, angle);
- * TuioPointer *tptr = server->addTuioToken(xpos,ypos);
- * TuioBounds *tbnd = server->addTuioBounds(xpos,ypos,width,height,angle);
- * server->commitFrame();
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * server->updateTuioToken(ttok, xpos,ypos, angle);
- * server->updateTuioPointer(tptr, xpos,ypos);
- * server->updateTuioBounds(tbnd, xpos,ypos,width,height,angle);
- * server->commitFrame();
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * server->removeTuioToken(ttok);
- * server->removeTuioPointer(tptr);
- * server->removeTuioBounds(tbnd);
- * server->commitFrame();
- *

- * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - class LIBDECL TuioManager : public TuioDispatcher { - - public: - - /** - * The default constructor creates a TuioManager - */ - TuioManager(); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioManager(); - - /** - * Adds an externally managed TuioObject to the TuioServer's internal list of active TuioObjects - * - * @param tobj the TuioObject to add - */ - void addExternalTuioObject(TuioObject *tobj); - - /** - * Updates an externally managed TuioObject - * - * @param tobj the TuioObject to update - */ - void updateExternalTuioObject(TuioObject *tobj); - - /** - * Removes an externally managed TuioObject from the TuioServer's internal list of TuioObjects - * The referenced TuioObject is not deleted - * - * @param tobj the TuioObject to remove - */ - void removeExternalTuioObject(TuioObject *tobj); - - /** - * Creates an internally managed TuioObject with a new Session ID - * and adds it to the TuioServer's internal list of TuioObjects - * - * @return the newly created but empty TuioObject - */ - TuioObject* createTuioObject(); - - /** - * Removes an internally managed TuioObject from the TuioServer's internal list of TuioObjects - * The provided TuioObject (and all its encapsulated TUIO Components) are deleted - * - * @param s_id the Session ID of the internal TuioObject to remove - */ - void removeTuioObject(unsigned int s_id); - - /** - * Removes an internally managed TuioObject from the TuioServer's internal list of TuioObjects - * The provided TuioObject (and all its encapsulated TUIO Components) are deleted - * - * @param tobj the internal TuioObject to remove - */ - void removeTuioObject(TuioObject *tobj); - - /** - * Creates a new TuioToken based on the given arguments. - * A new TuioObject containing that TuioToken is added - * to the TuioServer's internal list of TuioObjects - * and the TuioToken reference is returned to the caller. - * - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @return reference to the created TuioToken - */ - TuioObject* createTuioToken(unsigned int sym, float xp, float yp, float a); - - /** - * Creates a new TuioToken based on the given arguments. - * A new TuioObject containing that TuioToken is added - * to the TuioServer's internal list of TuioObjects - * and the TuioToken reference is returned to the caller. - * - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @return a reference to the TuioObject of the TuioToken - */ - TuioObject* createTuioToken(unsigned int sym, unsigned short t_id, unsigned short u_id, float xp, float yp, float a); - - /** - * Creates a new TuioToken based on the given arguments. - * and adds it to an existing TuioObject with the Session ID - * from the TuioServer's internal list of TuioObjects - * and the TuioToken reference is returned to the caller. - * - * @param tobj the existing TuioObject - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @return a reference to the TuioObject of the TuioToken - */ - TuioObject* addTuioToken(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, float xp, float yp, float a); - - /** - * Creates a new TuioToken based on the given arguments. - * and adds it to an existing TuioObject with the Session ID - * from the TuioServer's internal list of TuioObjects - * and the TuioToken reference is returned to the caller. - * - * @param tobj the existing TuioObject - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @return a reference to the TuioObject of the TuioToken - */ - TuioObject* addTuioToken(TuioObject *tobj, unsigned int sym, float xp, float yp, float a); - - /** - * Adds the provided TuioToken to an existing TuioObject - * from the TuioServer's internal list of TuioObjects - * or creates the according TuioObject if not found. - * - * @param ttok the existing TuioToken to add - * @return a reference to the TuioObject of the TuioToken - */ - TuioObject* addTuioToken(TuioToken *ttok); - - /** - * Updates the referenced TuioToken based on the given arguments. - * - * @param ttok the TuioToken to update - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - void updateTuioToken(TuioToken *ttok, float xp, float yp, float a); - - /** - * Removes the provided TuioToken from an existing TuioObject - * and also deletes the TuioObject with all other components - * - * @param ttok the TuioToken to remove - */ - void removeTuioToken(TuioToken *ttok); - - /** - * Creates a new TuioPointer based on the given arguments. - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference is returned to the caller. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return a reference to the TuioObject of the TuioPointer - */ - TuioObject* createTuioPointer(float xp, float yp, float a, float s, float r, float p); - - /** - * Creates a new TuioPointer based on the given arguments. - * and adds it to an existing TuioObject with the Session ID - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference of the TuioObject is returned to the caller. - * - * @param tobj the existing TuioObject - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return a reference to the TuioObject of the TuioPointer - */ - TuioObject* addTuioPointer(TuioObject *tobj, float xp, float yp, float a, float s, float r, float p); - - /** - * Creates a new TuioPointer based on the given arguments. - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference is returned to the caller. - * - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return a reference to the TuioObject of the TuioPointer - */ - TuioObject* createTuioPointer(unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); - - /** - * Creates a new TuioPointer based on the given arguments. - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference is returned to the caller. - * - * @param tobj the existing TuioObject - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return a reference to the TuioObject of the TuioPointer - */ - TuioObject* addTuioPointer(TuioObject *tobj, unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); - - /** - * Creates a new TuioPointer based on the given arguments. - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference is returned to the caller. - * - * @param p_id the Pointer ID to assign - * @param xp the X coordinate to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return reference to the created TuioPointer - */ - TuioObject* createTuioPointer(unsigned int p_id, float xp, float yp, float a, float s, float r, float p); - - /** - * Creates a new TuioPointer based on the given arguments. - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference is returned to the caller. - * - * @param tobj the existing TuioObject - * @param p_id the Pointer ID to assign - * @param xp the X coordinate to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return reference to the created TuioPointer - */ - TuioObject* addTuioPointer(TuioObject *tobj, unsigned int p_id, float xp, float yp, float a, float s, float r, float p); - - /** - * Creates a new TuioPointer based on the given arguments. - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference is returned to the caller. - * - * @param p_id the Pointer ID to assign - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param xp the X coordinate to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return a reference to the TuioObject of the TuioPointer - */ - TuioObject* createTuioPointer(unsigned int p_id, unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); - - /** - * Creates a new TuioPointer based on the given arguments. - * The new TuioPointer is added to the TuioServer's internal list of active TuioPointers - * and a reference is returned to the caller. - * - * @param tobj the existing TuioObject - * @param p_id the Pointer ID to assign - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param xp the X coordinate to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @return a reference to the TuioObject of the TuioPointer - */ - TuioObject* addTuioPointer(TuioObject *tobj, unsigned int p_id, unsigned short t_id, unsigned short u_id, float xp, float yp, float a, float s, float r, float p); - - /** - * Adds the provided TuioPointer to an existing TuioObject - * from the TuioServer's internal list of TuioObjects - * or creates the according TuioObject if not found. - * - * @param tptr the existing TuioPointer to add - * @return a reference to the TuioObject of the TuioPointer - */ - TuioObject* addTuioPointer(TuioPointer *tptr); - - /** - * Updates the referenced TuioPointer based on the given arguments. - * - * @param tptr the TuioPointer to update - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the rotation angle to assign - * @param s the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - */ - void updateTuioPointer(TuioPointer *tptr, float xp, float yp, float a, float s, float r, float p); - - /** - * Removes the provided TuioPointer from an existing TuioObject - * and also deletes the TuioObject with all other components - * - * @param tptr the TuioPointer to remove - */ - void removeTuioPointer(TuioPointer *tptr); - - /** - * Creates a new TuioBounds based on the given arguments. - * The new TuioBounds is added to the TuioServer's internal list of active TuioBounds - * and a reference is returned to the caller. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param angle the angle to assign - * @param width the width to assign - * @param height the height to assign - * @param area the area to assign - * @return a reference to the TuioObject of the TuioBounds - */ - TuioObject* createTuioBounds(float xp, float yp, float angle, float width, float height, float area); - - /** - * Creates a new TuioBounds based on the given arguments. - * The new TuioBounds is added to the TuioServer's internal list of active TuioBounds - * and a reference is returned to the caller. - * - * @param tobj the existing TuioObject - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param angle the angle to assign - * @param width the width to assign - * @param height the height to assign - * @param area the area to assign - * @return a reference to the TuioObject of the TuioBounds - */ - TuioObject* addTuioBounds(TuioObject *tobj, float xp, float yp, float angle, float width, float height, float area); - - /** - * Adds the provided TuioBounds to an existing TuioObject - * from the TuioServer's internal list of TuioObjects - * or creates the according TuioObject if not found. - * - * @param tbnd the TuioBounds to add - * @return a reference to the TuioObject of the TuioBounds - */ - TuioObject* addTuioBounds(TuioBounds *tbnd); - - /** - * Updates the referenced TuioBounds based on the given arguments. - * - * @param tbnd the TuioToken to update - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param angle the angle to assign - * @param width the width to assign - * @param height the height to assign - * @param area the area to assign - */ - void updateTuioBounds(TuioBounds *tbnd, float xp, float yp, float angle, float width, float height, float area); - - /** - * Removes the referenced TuioBounds from the TuioServer's internal list of TuioObjects - * and also deletes its TuioObject (and all its encapsulated TUIO Components) - * - * @param tbnd the TuioBounds to remove - */ - void removeTuioBounds(TuioBounds *tbnd); - - /** - * Creates a new TuioSymbol based on the given arguments. - * The new TuioSymbol is added to the TuioServer's internal list of TuioObjects - * and a reference is returned to the caller. - * - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param sym the Symbol ID to assign - * @param type the type descriptor to assign - * @param data the synbol data to assign - * @return a reference to the TuioObject of the TuioSymbol - */ - TuioObject* createTuioSymbol(unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data); - - /** - * Creates a new TuioSymbol based on the given arguments. - * The new TuioSymbol is added to the TuioServer's internal list of TuioObjects - * and a reference is returned to the caller. - * - * @param tobj the existing TuioObject - * @param t_id the Type ID to assign - * @param u_id the User ID to assign - * @param sym the Symbol ID to assign - * @param type the type descriptor to assign - * @param data the synbol data to assign - * @return a reference to the TuioObject of the TuioSymbol - */ - TuioObject* addTuioSymbol(TuioObject *tobj, unsigned short t_id, unsigned short u_id, unsigned int sym, const char *type, const char *data); - - /** - * Adds the provided TuioSymbol to an existing TuioObject - * from the TuioServer's internal list of TuioObjects - * or creates the according TuioObject if not found. - * - * @param tsym the TuioSymbol to add - * @return a reference to the TuioObject of the TuioSymbol - */ - TuioObject* addTuioSymbol(TuioSymbol *tsym); - - /** - * Removes the referenced TuioSymbol from the TuioServer's internal list of TuioObjects - * and also deletes its TuioObject (and all its encapsulated TUIO Components) - * - * @param tsym the TuioSymbol to remove - */ - void removeTuioSymbol(TuioSymbol *tsym); - - /** - * Initializes a new frame with the given TuioTime - * - * @param ttime the frame time - */ - void initTuioFrame(TuioTime ttime); - - /** - * Commits the current frame. - * Generates and sends TUIO messages of all currently active and updated TuioTokens and TuioPointers. - */ - void commitTuioFrame(); - - /** - * Returns the next available Session ID for external use. - * @return the next available Session ID for external use - */ - int getSessionID(); - - /** - * Returns the current frame ID for external use. - * @return the current frame ID for external use - */ - int getFrameID(); - - /** - * Returns the current frame time for external use. - * @return the current frame time for external use - */ - TuioTime getFrameTime(); - - /** - * Returns a List of all currently inactive TuioObjects - * - * @return a List of all currently inactive TuioObjects - */ - std::list getUntouchedObjects(); - - /** - * Calculates speed and acceleration values for all currently inactive TuioObjects - */ - void stopUntouchedMovingObjects(); - - /** - * Removes all currently inactive TuioObjects from the TuioServer's internal list - */ - void removeUntouchedStoppedObjects(); - - /** - * Returns the TuioToken closest to the provided coordinates - * or NULL if there isn't any active TuioToken - * - * @return the closest TuioToken to the provided coordinates or NULL - */ - TuioToken* getClosestTuioToken(float xp, float yp); - - /** - * Returns the TuioPointer closest to the provided coordinates - * or NULL if there isn't any active TuioPointer - * - * @return the closest TuioPointer corresponding to the provided coordinates or NULL - */ - TuioPointer* getClosestTuioPointer(float xp, float yp); - - /** - * Returns the TuioBounds closest to the provided coordinates - * or NULL if there isn't any active TuioBounds - * - * @return the closest TuioBounds corresponding to the provided coordinates or NULL - */ - TuioBounds* getClosestTuioBounds(float xp, float yp); - - /** - * The TuioServer prints verbose TUIO event messages to the console if set to true. - * @param verbose print verbose messages if set to true - */ - void setVerbose(bool verbose) { this->verbose=verbose; } - - void setInversion(bool ix, bool iy, bool ia) { - invert_x = ix; - invert_y = iy; - invert_a = ia; - }; - - void setInvertXpos(bool ix) { invert_x = ix; }; - void setInvertYpos(bool iy) { invert_y = iy; }; - void setInvertAngle(bool ia) { invert_a = ia; }; - bool getInvertXpos() { return invert_x; }; - bool getInvertYpos() { return invert_y; }; - bool getInvertAngle() { return invert_a; }; - void resetTuioObjectList(); - - protected: - std::list freePointerList; - std::list freePointerBuffer; - - TuioTime currentFrameTime; - osc::TimeTag frameTimeTag; - unsigned int currentFrame; - unsigned int pointerCount, maxPointerID; - unsigned int sessionID; - - bool tobjUpdate; - bool verbose; - - bool invert_x; - bool invert_y; - bool invert_a; - }; -} -#endif /* INCLUDED_TUIOMANAGER_H */ diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp deleted file mode 100644 index 15836c1b4f..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioObject.h" - -using namespace TUIO2; - -TuioObject::TuioObject (unsigned int s_id) { - currentTime = TuioTime::getSystemTime(); - session_id = s_id; - startTime = currentTime; - - token = NULL; - pointer = NULL; - bounds = NULL; - symbol = NULL; - state = TUIO_ADDED; -} - -TuioObject::TuioObject (TuioTime ttime, unsigned int s_id) { - currentTime = ttime; - session_id = s_id; - startTime = currentTime; - - token = NULL; - pointer = NULL; - bounds = NULL; - symbol = NULL; - state = TUIO_ADDED; -} - -TuioObject::TuioObject (TuioTime ttime, TuioSource *src, unsigned int s_id) { - currentTime = ttime; - session_id = s_id; - startTime = currentTime; - - setTuioSource(src); - token = NULL; - pointer = NULL; - bounds = NULL; - symbol = NULL; - state = TUIO_ADDED; -} - -TuioObject::~TuioObject() { - deleteAllTuioComponents(); -} - -unsigned int TuioObject::getSessionID() { - return session_id; -} - -void TuioObject::setTuioSource(TuioSource *src) { - source.setSourceString(src->getSourceID(),src->getSourceString()); -} - -TuioSource* TuioObject::getTuioSource() { - return &source; -} - -void TuioObject::setTuioToken (TuioToken *ttok) { - token = ttok; - token->setContainingTuioObject(this); - currentTime = TuioTime::getSystemTime(); - state = TUIO_ADDED; -} - -void TuioObject::setTuioPointer (TuioPointer *tptr) { - pointer = tptr; - pointer->setContainingTuioObject(this); - currentTime = TuioTime::getSystemTime(); - state = TUIO_ADDED; -} - -void TuioObject::setTuioBounds (TuioBounds *tbnd) { - bounds = tbnd; - bounds->setContainingTuioObject(this); - currentTime = TuioTime::getSystemTime(); - state = TUIO_ADDED; -} - -void TuioObject::setTuioSymbol (TuioSymbol *tsym) { - symbol = tsym; - symbol->setContainingTuioObject(this); - currentTime = TuioTime::getSystemTime(); - state = TUIO_ADDED; -} - -void TuioObject::removeAllTuioComponents(TuioTime ttime) { - removeTuioToken(ttime); - removeTuioPointer(ttime); - removeTuioBounds(ttime); - removeTuioSymbol(ttime); -} - -void TuioObject::removeTuioToken (TuioTime ttime) { - if (token != NULL) token->remove(ttime); - currentTime = ttime; - } - -void TuioObject::removeTuioPointer (TuioTime ttime) { - if (pointer != NULL) pointer->remove(ttime); - currentTime = ttime; -} - -void TuioObject::removeTuioBounds (TuioTime ttime) { - if (bounds != NULL) bounds->remove(ttime); - currentTime = ttime; -} - -void TuioObject::removeTuioSymbol (TuioTime ttime) { - if (symbol != NULL) symbol->remove(ttime); - currentTime = ttime; -} - -void TuioObject::deleteAllTuioComponents() { - deleteTuioToken(); - deleteTuioPointer(); - deleteTuioBounds(); - deleteTuioSymbol(); -} - -void TuioObject::deleteTuioToken () { - if (token != NULL) { - delete token; - token = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -void TuioObject::deleteTuioPointer () { - if (pointer != NULL) { - delete pointer; - pointer = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -void TuioObject::deleteTuioBounds () { - if (bounds != NULL) { - delete bounds; - bounds = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -void TuioObject::deleteTuioSymbol () { - if (symbol != NULL) { - delete symbol; - symbol = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -void TuioObject::clearAllTuioComponents() { - clearTuioToken(); - clearTuioPointer(); - clearTuioBounds(); - clearTuioSymbol(); -} - -void TuioObject::clearTuioToken () { - if (token != NULL) { - token = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -void TuioObject::clearTuioPointer () { - if (pointer != NULL) { - pointer = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -void TuioObject::clearTuioBounds () { - if (bounds != NULL) { - bounds = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -void TuioObject::clearTuioSymbol () { - if (symbol != NULL) { - symbol = NULL; - //currentTime = TuioTime::getSessionTime(); - } -} - -bool TuioObject::containsAnyTuioComponent () { - if (token != NULL) return true; - else if (pointer != NULL) return true; - else if (bounds != NULL) return true; - else if (symbol != NULL) return true; - else return false; -} - -bool TuioObject::containsTuioToken () { - if (token != NULL) return true; - else return false; -} - -bool TuioObject::containsTuioPointer () { - if (pointer != NULL) return true; - else return false; -} - -bool TuioObject::containsTuioBounds () { - if (bounds != NULL) return true; - else return false; -} - -bool TuioObject::containsTuioSymbol () { - if (symbol != NULL) return true; - else return false; -} - -bool TuioObject::containsNewTuioToken () { - if (token == NULL) return false; - else if (token->getTuioState()==TUIO_ADDED) return true; - else return false; -} - -bool TuioObject::containsNewTuioPointer () { - if (pointer == NULL) return false; - else if (pointer->getTuioState()==TUIO_ADDED) return true; - else return false; -} - -bool TuioObject::containsNewTuioBounds () { - if (bounds == NULL) return false; - else if (bounds->getTuioState()==TUIO_ADDED) return true; - else return false; -} - -bool TuioObject::containsNewTuioSymbol () { - if (symbol == NULL) return false; - else if (symbol->getTuioState()==TUIO_ADDED) return true; - else return false; -} - -TuioToken* TuioObject::getTuioToken () { - return token; -} - -TuioPointer* TuioObject::getTuioPointer () { - return pointer; -} - -TuioBounds* TuioObject::getTuioBounds () { - return bounds; -} - -TuioSymbol* TuioObject::getTuioSymbol () { - return symbol; -} - -void TuioObject::stop(TuioTime ttime){ - if (token!=NULL) token->stop(ttime); - if (pointer!=NULL) pointer->stop(ttime); - if (bounds!=NULL) bounds->stop(ttime); - currentTime = ttime; -} - -void TuioObject::remove(TuioTime ttime){ - if (token!=NULL) token->remove(ttime); - if (pointer!=NULL) pointer->remove(ttime); - if (bounds!=NULL) bounds->remove(ttime); - currentTime = ttime; - state = TUIO_REMOVED; -} - -void TuioObject::update(TuioTime ttime){ - currentTime = ttime; - state = TUIO_IDLE; -} - -bool TuioObject::isMoving(){ - if ((token!=NULL) && token->isMoving()) return true; - if ((pointer!=NULL) && pointer->isMoving()) return true; - if ((bounds!=NULL) && bounds->isMoving()) return true; - return false; -} - -TuioTime TuioObject::getTuioTime() const{ - return currentTime; -} - -TuioTime TuioObject::getStartTime() const{ - return startTime; -} - -unsigned char TuioObject::getTuioState() const{ - return state; -} - diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h b/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h deleted file mode 100644 index e3f141a9a7..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioObject.h +++ /dev/null @@ -1,347 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOOBJECT_H -#define INCLUDED_TUIOOBJECT_H - -#include "TuioTime.h" -#include "TuioToken.h" -#include "TuioPointer.h" -#include "TuioBounds.h" -#include "TuioSymbol.h" -#include "TuioSource.h" - -namespace TUIO2 { - - /** - * The TuioObject class encapsulates all Tuio objects that share the same Session ID. - * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - - class LIBDECL TuioObject { - - protected: - /** - * The shared session ID - */ - unsigned int session_id; - /** - * The associated TuioSource - */ - TuioSource source; - /** - * the associated TuioToken - */ - TuioToken *token; - /** - * the associated TuioPointer - */ - TuioPointer *pointer; - /** - * the associated TuioBounds - */ - TuioBounds *bounds; - /** - * the associated TuioSymbol - */ - TuioSymbol *symbol; - /** - * The time stamp of the last update represented as TuioTime (time since session start) - */ - TuioTime currentTime; - /** - * The creation time of this TuioObject represented as TuioTime (time since session start) - */ - TuioTime startTime; - /** - * Reflects the current state of the TuioObject - */ - unsigned char state; - - public: - /** - * The default constructor only takes the Session ID - * @param s_id the Session ID to assign - */ - TuioObject (unsigned int s_id); - - /** - * Copy constructor takes a reference of a TuioObject - * @param t the reference TuioObject to assign - */ - //TuioObject(const TuioObject &t); - - /** - * This constructor takes a TuioTime and the Session ID - * @param ttime the TuioTime to assign - * @param s_id the Session ID to assign - */ - TuioObject (TuioTime ttime, unsigned int s_id); - - /** - * This constructor takes a TuioTime and the Session ID - * @param ttime the TuioTime to assign - * @param src the TuioSource to assign - * @param s_id the Session ID to assign - */ - TuioObject (TuioTime ttime, TuioSource *src, unsigned int s_id); - - /** - * The default destructor also delets all assigned TUIO components - */ - ~TuioObject (); - - /** - * Returns the associated Session ID - * @return the associated Session ID - */ - unsigned int getSessionID(); - - /** - * Sets the assotiated TUIO source - * - * @param src the TuioSource to assign - */ - void setTuioSource(TuioSource *src); - - /** - * Returns the associated TUIO source - */ - TuioSource* getTuioSource(); - - /** - * This method assigns a TuioToken to this TuioObject - * @param ttok the TuioToken to assign - */ - void setTuioToken(TuioToken *ttok); - - /** - * This method assigns a TuioPointer to this TuioObject - * @param tptr the TuioPointer to assign - */ - void setTuioPointer(TuioPointer *tptr); - - /** - * This method assigns a TuioBounds to this TuioObject - * @param tbnd the TuioBounds to assign - */ - void setTuioBounds(TuioBounds *tbnd); - - /** - * This method assigns a TuioSymbol to this TuioObject - * @param tsym the TuioSymbol to assign - */ - void setTuioSymbol(TuioSymbol *tsym); - - /** - * This method sets all TuioComponents in this TuioObject to TUIO_REMOVED state - */ - void removeAllTuioComponents(TuioTime ttime); - - /** - * This method sets the TuioToken in this TuioObject to TUIO_REMOVED state - */ - void removeTuioToken(TuioTime ttime); - - /** - * This method sets the TuioPointer in this TuioObject to TUIO_REMOVED state - */ - void removeTuioPointer(TuioTime ttime); - - /** - * This method sets the TuioBounds in this TuioObject to TUIO_REMOVED state - */ - void removeTuioBounds(TuioTime ttime); - - /** - * This method sets the TuioSymbol in this TuioObject to TUIO_REMOVED state - */ - void removeTuioSymbol(TuioTime ttime); - - /** - * This method deletes all TuioComponents in this TuioObject - */ - void deleteAllTuioComponents(); - - /** - * This method deletes the TuioToken in this TuioObject - */ - void deleteTuioToken(); - - /** - * This method deletes the TuioPointer in this TuioObject - */ - void deleteTuioPointer(); - - /** - * This method deletes the TuioBounds in this TuioObject - */ - void deleteTuioBounds(); - - /** - * This method deletes the TuioSymbol in this TuioObject - */ - void deleteTuioSymbol(); - - /** - * This method clears all TuioComponents in this TuioObject - */ - void clearAllTuioComponents(); - - /** - * This method clears the TuioToken in this TuioObject - */ - void clearTuioToken(); - - /** - * This method clears the TuioPointer in this TuioObject - */ - void clearTuioPointer(); - - /** - * This method clears the TuioBounds in this TuioObject - */ - void clearTuioBounds(); - - /** - * This method clears the TuioSymbol in this TuioObject - */ - void clearTuioSymbol(); - - /** - * This method tests for any TuioComponent in this TuioObject - * @return true if any TuioComponent has been assigned - */ - bool containsAnyTuioComponent(); - - /** - * This method tests for a TuioToken in this TuioObject - * @return true if a TuioToken has been assigned - */ - bool containsTuioToken(); - - /** - * This method tests for a TuioPointer in this TuioObject - * @return true if a TuioPointer has been assigned - */ - bool containsTuioPointer(); - - /** - * This method tests for a TuioBounds in this TuioObject - * @return true if a TuioBounds has been assigned - */ - bool containsTuioBounds(); - - /** - * This method tests for a TuioSymbol in this TuioObject - * @return true if a TuioSymbol has been assigned - */ - bool containsTuioSymbol(); - - /** - * This method tests if a new TuioToken has been added to this TuioObject - * @return true if a TuioToken has been added - */ - bool containsNewTuioToken(); - - /** - * This method tests if a new TuioPointer has been added this TuioObject - * @return true if a TuioPointer has been added - */ - bool containsNewTuioPointer(); - - /** - * This method tests if a new TuioBounds has been added to this TuioObject - * @return true if a TuioBounds has been added - */ - bool containsNewTuioBounds(); - - /** - * This method tests if a new TuioSymbol has beed added to this TuioObject - * @return true if a TuioSymbol has been added - */ - bool containsNewTuioSymbol(); - - /** - * This method returns the TuioToken associated to this TuioObject - * @return the associated TuioToken - */ - TuioToken* getTuioToken(); - - /** - * This method returns the TuioPointer associated to this TuioObject - * @return the associated TuioPointer - */ - TuioPointer* getTuioPointer(); - - /** - * This method returns the TuioBounds associated to this TuioObject - * @return the associated TuioBounds - */ - TuioBounds* getTuioBounds(); - - /** - * This method returns the TuioSymbol associated to this TuioObject - * @return the associated TuioSymbol - */ - TuioSymbol* getTuioSymbol(); - - /** - * This method stops all encapsulated TuioComponents - */ - void stop(TuioTime ttime); - - /** - * This method removes all encapsulated TuioComponents - */ - void remove(TuioTime ttime); - - /** - * This method returns true if any encapsulated TuioComponent is moving - */ - bool isMoving(); - - /** - * This method refreshes the currentTime after an update - */ - void update(TuioTime ttime); - - /** - * Returns current time stamp of this TuioPoint as TuioTime - * - * @return the time stamp of this TuioPoint as TuioTime - */ - TuioTime getTuioTime() const; - - /** - * Returns the start time of this TuioPoint as TuioTime. - * - * @return the start time of this TuioPoint as TuioTime - */ - TuioTime getStartTime() const; - - /** - * Returns the TUIO state of this TuioObject. - * @return the TUIO state of this TuioObject - */ - unsigned char getTuioState() const; - }; -} -#endif // INCLUDED_TUIOOBJECT_H diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp deleted file mode 100644 index ffdb5066da..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioPointer.h" - -using namespace TUIO2; - -TuioPointer::TuioPointer (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p):TuioComponent(ttime,tobj,xp,yp,a) { - type_id = ti; - user_id = ui; - pointer_id = pi; - shear = sa; - radius = r; - pressure = p; -} - -TuioPointer::TuioPointer (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p):TuioComponent(tobj,xp,yp,a) { - type_id = ti; - user_id = ui; - shear = sa; - pointer_id = pi; - radius = r; - pressure = p; -} - -TuioPointer::TuioPointer (TuioObject *tobj, unsigned int pi, float xp, float yp, float a, float sa, float r, float p):TuioComponent(tobj,xp,yp,a) { - type_id = 0; - user_id = 0; - pointer_id = pi; - shear = sa; - radius = r; - pressure = p; -} - -TuioPointer::TuioPointer (TuioPointer *tptr):TuioComponent(tptr) { - pointer_id = tptr->getPointerID(); - type_id = tptr->getTypeID(); - user_id = tptr->getUserID(); - shear = tptr->getShear(); - radius = tptr->getRadius(); - pressure = tptr->getPressure(); -} - -void TuioPointer::update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa) { - TuioComponent::update(ttime,xp,yp,a,xs,ys,0,ma,0); - shear = sa; - radius = r; - pressure = p; - pressure_speed = ps; - pressure_accel = pa; -} - -void TuioPointer::update (float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa) { - TuioComponent::update(xp,yp,a,xs,ys,0,ma,0); - shear = sa; - radius = r; - pressure = p; - pressure_speed = ps; - pressure_accel = pa; -} - -void TuioPointer::update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p) { - TuioComponent::update(ttime,xp,yp,a); - shear = sa; - radius = r; - pressure = p; -} - -void TuioPointer::update (TuioPointer *tptr) { - TuioComponent::update(tptr); - shear = tptr->getShear(); - radius = tptr->getRadius(); - pressure = tptr->getPressure(); -} - -unsigned int TuioPointer::getPointerID() const{ - return pointer_id; -}; - -unsigned short TuioPointer::getTypeID() const{ - return type_id; -}; - -unsigned short TuioPointer::getUserID() const{ - return user_id; -}; - -unsigned int TuioPointer::getTypeUserID() const { - int tu_id = user_id << 16 | type_id; - return tu_id; -} - -void TuioPointer::setTypeUserID(unsigned int tu_id) { - user_id = tu_id >> 16; - type_id = tu_id & 0x0000FFFF; -} - -float TuioPointer::getShear() const{ - return shear; -}; - -float TuioPointer::getRadius() const{ - return radius; -}; - -float TuioPointer::getPressure() const{ - return pressure; -}; - -float TuioPointer::getPressureSpeed() const{ - return pressure_speed; -} - -float TuioPointer::getPressureAccel() const{ - return pressure_accel; -} - diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h b/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h deleted file mode 100644 index 43ffe72caf..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioPointer.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOPOINTER_H -#define INCLUDED_TUIOPOINTER_H - -#include "TuioComponent.h" - -namespace TUIO2 { - - /** - * The TuioPointer class encapsulates /tuio2/ptr TUIO pointers. - * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - - class LIBDECL TuioPointer: public TuioComponent { - - protected: - /** - * The individual pointer ID number that is assigned to each TuioPointer. - */ - unsigned int pointer_id; - - /** - * The pointer type ID that is assigned to each TuioPointer. - */ - unsigned short type_id; - - /** - * The user ID that is assigned to each TuioPointer. - */ - unsigned short user_id; - - /** - * The shear angle that is assigned to each TuioPointer. - */ - float shear; - - /** - * The action radius that is assigned to each TuioPointer. - */ - float radius; - - /** - * The pressure that is assigned to each TuioPointer. - */ - float pressure; - - /** - * The pressure speed value. - */ - float pressure_speed; - - /** - * The pressure acceleration value. - */ - float pressure_accel; - - public: - using TuioComponent::update; - - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, Pointer ID, X and Y coordinate to the newly created TuioPointer. - * - * @param ttime the TuioTime to assign - * @param tobj the TuioObject to assign - * @param ti the Type ID to assign - * @param ui the User ID to assign - * @param pi the Pointer ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @param sa the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - */ - TuioPointer (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p); - - /** - * This constructor takes the provided Session ID, Pointer ID, X and Y coordinate - * and assigs these values to the newly created TuioPointer. - * - * @param tobj the TuioObject to assign - * @param ti the Type ID to assign - * @param ui the User ID to assign - * @param pi the Pointer ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @param sa the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - */ - TuioPointer (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int pi, float xp, float yp, float a, float sa, float r, float p); - - - /** - * This constructor takes the provided Session ID, Pointer ID, X and Y coordinate - * and assigs these values to the newly created TuioPointer. - * - * @param tobj the TuioObject to assign - * @param pi the Pointer ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @param sa the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - */ - TuioPointer (TuioObject *tobj, unsigned int pi, float xp, float yp, float a, float sa, float r, float p); - - /** - * This constructor takes the atttibutes of the provided TuioPointer - * and assigs these values to the newly created TuioPointer. - * - * @param tptr the TuioPointer to assign - */ - TuioPointer (TuioPointer *tptr); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioPointer(){}; - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate, width, pressure, X and Y velocity, motion acceleration, - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @param sa the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param ps the pressure velocity to assign - * @param ma the motion acceleration to assign - * @param pa the pressure acceleration to assign - */ - void update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa); - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate, width, pressure, X and Y velocity, motion acceleration, - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @param sa the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param ps the pressure velocity to assign - * @param ma the motion acceleration to assign - * @param pa the pressure acceleration to assign - */ - void update (float xp, float yp, float a, float sa, float r, float p, float xs, float ys, float ps, float ma, float pa); - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate and angle to the private TuioToken attributes. - * The speed and accleration values are calculated accordingly. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @param sa the shear angle to assign - * @param r the radius to assign - * @param p the pressure to assign - */ - void update (TuioTime ttime, float xp, float yp, float a, float sa, float r, float p); - - /** - * Takes the atttibutes of the provided TuioPointer - * and assigs these values to this TuioPointer. - * The TuioTime time stamp of this TuioComponent remains unchanged. - * - * @param ttok the TuioComponent to assign - */ - void update (TuioPointer *tptr); - - /** - * Returns the Pointer ID of this TuioPointer. - * @return the Pointer ID of this TuioPointer - */ - unsigned int getPointerID() const; - - /** - * Returns the Type ID of this TuioPointer. - * @return the Type ID of this TuioPointer - */ - unsigned short getTypeID() const; - - /** - * Returns the User ID of this TuioPointer. - * @return the User ID of this TuioPointer - */ - unsigned short getUserID() const; - - /** - * Returns the encoded Type & User ID of this TuioPointer. - * @return the encoded Type & User ID of this TuioPointer - */ - unsigned int getTypeUserID() const; - - /** - * Decodes and assigns the Type & User ID to this TuioPointer. - * @param tu_id the encoded Type & User ID of this TuioPointer - */ - void setTypeUserID(unsigned int tu_id); - - /** - * Returns the shear angle of this TuioPointer. - * @return the shear angle of this TuioPointer - */ - float getShear() const; - - /** - * Returns the action radius of this TuioPointer. - * @return the action radius of this TuioPointer - */ - float getRadius() const; - - /** - * Returns the Pressure of this TuioPointer. - * @return the Pressure of this TuioPointer - */ - float getPressure() const; - - /** - * Returns the pressure speed of this TuioPointer. - * @return the pressure speed of this TuioPointer - */ - float getPressureSpeed() const; - - /** - * Returns the pressure acceleration of this TuioPointer. - * @return the pressure acceleration of this TuioPointer - */ - float getPressureAccel() const; - }; -} -#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp deleted file mode 100644 index 9d599f774f..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioServer.cpp +++ /dev/null @@ -1,329 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioServer.h" -#include "UdpSender.h" - -using namespace TUIO2; -using namespace osc; - -TuioServer::TuioServer() - :local_sender (true) - ,full_update (false) - ,periodic_update (false) - ,source (NULL) -{ - primary_sender = new UdpSender(); - initialize(); -} - -TuioServer::TuioServer(const char *host, unsigned short port) -:local_sender (true) -,full_update (false) -,periodic_update (false) -,source (NULL) -{ - primary_sender = new UdpSender(host,port); - initialize(); -} - -TuioServer::TuioServer(OscSender *oscsend) - :primary_sender (oscsend) - ,local_sender (false) - ,full_update (false) - ,periodic_update (false) - ,source (NULL) -{ - initialize(); -} - -void TuioServer::initialize() { - - senderList.push_back(primary_sender); - int size = primary_sender->getBufferSize(); - oscBuffer = new char[size]; - oscPacket = new osc::OutboundPacketStream(oscBuffer,size); - fullBuffer = new char[size]; - fullPacket = new osc::OutboundPacketStream(oscBuffer,size); - - updateTime = TuioTime(currentFrameTime); - //sendEmptyTuioBundle(); - - invert_x = false; - invert_y = false; - invert_a = false; -} - -TuioServer::~TuioServer() { - - initTuioFrame(TuioTime::getSystemTime()); - stopUntouchedMovingObjects(); - - initTuioFrame(TuioTime::getSystemTime()); - removeUntouchedStoppedObjects(); - sendEmptyTuioBundle(); - - delete []oscBuffer; - delete oscPacket; - delete []fullBuffer; - delete fullPacket; - - if (local_sender) delete primary_sender; -} - -void TuioServer::addOscSender(OscSender *sender) { - - // add source address if previously local - /*if ((source_name) && (primary_sender->isLocal()) && (senderList.size()==1)) { - setSourceName(source_name); - }*/ - - // resize packets to smallest transport method - unsigned int size = sender->getBufferSize(); - if (sizeCapacity()) { - osc::OutboundPacketStream *temp = oscPacket; - oscPacket = new osc::OutboundPacketStream(oscBuffer,size); - delete temp; - temp = fullPacket; - fullPacket = new osc::OutboundPacketStream(oscBuffer,size); - delete temp; - - } - - senderList.push_back(sender); -} - -void TuioServer::deliverOscPacket(osc::OutboundPacketStream *packet) { - - for (unsigned int i=0;isendOscPacket(packet); -} - -void TuioServer::setSourceName(const char* name) { - if (source==NULL) source = new TuioSource(name); - //else source->setSourceName(name); -} - -void TuioServer::setDimension(unsigned short w, unsigned short h) { - if (source!=NULL) source->setDimension(w,h); - - // decoder test - /*int dim = source->getDimension(); - short width = dim >> 16; - short height = dim & 0x0000FFFF; - printf("dim: %i %i\n",width,height);*/ -} - -void TuioServer::commitTuioFrame() { - TuioManager::commitTuioFrame(); - - if(tobjUpdate) { - startTuioBundle(currentFrame); - for (std::list::iterator tobj = tobjList.begin(); tobj!=tobjList.end(); tobj++) { - - if ((*tobj)->containsTuioToken()) { - TuioToken *ttok = (*tobj)->getTuioToken(); - if ((full_update) || (ttok->getTuioTime()==currentFrameTime)) addTokenMessage(ttok); - } - - if ((*tobj)->containsTuioPointer()) { - TuioPointer *tptr = (*tobj)->getTuioPointer(); - if ((full_update) || (tptr->getTuioTime()==currentFrameTime)) addPointerMessage(tptr); - } - - if ((*tobj)->containsTuioBounds()) { - TuioBounds *tbnd = (*tobj)->getTuioBounds(); - if ((full_update) || (tbnd->getTuioTime()==currentFrameTime)) addBoundsMessage(tbnd); - } - - if ((*tobj)->containsTuioSymbol()) { - TuioSymbol *tsym = (*tobj)->getTuioSymbol(); - if ((full_update) || (tsym->getTuioTime()==currentFrameTime)) addSymbolMessage(tsym); - } - - - } - updateTime = TuioTime(currentFrameTime); - sendTuioBundle(); - } else if (periodic_update) { - - TuioTime timeCheck = currentFrameTime - updateTime; - if(timeCheck.getSeconds()>=update_interval) { - updateTime = TuioTime(currentFrameTime); - startTuioBundle(currentFrame); - if (full_update) { - for (std::list::iterator tobj = tobjList.begin(); tobj!=tobjList.end(); tobj++) { - // start a new packet if we exceed the packet capacity - if ((oscPacket->Capacity()-oscPacket->Size())getTuioToken()); - } - } - sendTuioBundle(); - } - } - tobjUpdate = false; -} - -void TuioServer::sendEmptyTuioBundle() { - oscPacket->Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - (*oscPacket) << osc::BeginMessage( "/tuio2/frm") << 0 << TuioTime::getSystemTimeTag() << (int32)source->getDimension() << source->getSourceName() << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio2/alv") << osc::EndMessage; - (*oscPacket) << osc::EndBundle; - deliverOscPacket( oscPacket ); -} - -void TuioServer::sendFullTuioBundle() { - -} - -void TuioServer::checkBundleCapacity(int msg_size) { - - int size = msg_size + ALV_MESSAGE_SIZE + 4*tobjList.size(); - - if ((oscPacket->Capacity()-oscPacket->Size())Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - if (source) (*oscPacket) << osc::BeginMessage( "/tuio2/frm") << (int32)currentFrame << frameTimeTag << (int32)source->getDimension() << source->getSourceName(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::addTokenMessage(TuioToken *ttok) { - - // start a new packet if we exceed the packet capacity - checkBundleCapacity(TOK_MESSAGE_SIZE); - - float xpos = ttok->getX(); - float xvel = ttok->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = ttok->getY(); - float yvel = ttok->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - float angle = ttok->getAngle(); - float rvel = ttok->getRotationSpeed(); - if (invert_a) { - angle = 2.0f*(float)M_PI - angle; - rvel = -1 * rvel; - } - - (*oscPacket) << osc::BeginMessage( "/tuio2/tok"); - (*oscPacket) << (int32)ttok->getSessionID() << (int32)ttok->getTypeUserID() << (int32)ttok->getSymbolID() << xpos << ypos << angle; - (*oscPacket) << xvel << yvel << rvel << ttok->getMotionAccel() << ttok->getRotationAccel(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::addPointerMessage(TuioPointer *tptr) { - - // start a new packet if we exceed the packet capacity - checkBundleCapacity(PTR_MESSAGE_SIZE); - - float xpos = tptr->getX(); - float xvel = tptr->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = tptr->getY(); - float yvel = tptr->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - - (*oscPacket) << osc::BeginMessage( "/tuio2/ptr"); - (*oscPacket) << (int32)tptr->getSessionID() << (int32)tptr->getTypeUserID() << (int32)tptr->getPointerID(); - (*oscPacket) << xpos << ypos << tptr->getAngle() << tptr->getShear() << tptr->getRadius() << tptr->getPressure(); - (*oscPacket) << xvel << yvel << tptr->getPressureSpeed() << tptr->getMotionAccel() << tptr->getPressureAccel(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::addBoundsMessage(TuioBounds *tbnd) { - - // start a new packet if we exceed the packet capacity - checkBundleCapacity(BND_MESSAGE_SIZE); - - float xpos = tbnd->getX(); - float xvel = tbnd->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = tbnd->getY(); - float yvel = tbnd->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - float angle = tbnd->getAngle(); - float rvel = tbnd->getRotationSpeed(); - if (invert_a) { - angle = 2.0f*(float)M_PI - angle; - rvel = -1 * rvel; - } - - (*oscPacket) << osc::BeginMessage( "/tuio2/bnd"); - (*oscPacket) << (int32)tbnd->getSessionID() << xpos << ypos << angle << tbnd->getWidth() << tbnd->getHeight() << tbnd->getArea(); - (*oscPacket) << xvel << yvel << rvel << tbnd->getMotionAccel() << tbnd->getRotationAccel(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::addSymbolMessage(TuioSymbol *tsym) { - - // start a new packet if we exceed the packet capacity - checkBundleCapacity(SYM_MESSAGE_SIZE); - - (*oscPacket) << osc::BeginMessage( "/tuio2/sym"); - (*oscPacket) << (int32)tsym->getSessionID() << (int32)tsym->getTypeUserID() << (int32)tsym->getSymbolID(); - (*oscPacket) << tsym->getSymbolType() << tsym->getSymbolData(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::sendTuioBundle() { - - //int before = oscPacket->Capacity()-oscPacket->Size(); - (*oscPacket) << osc::BeginMessage( "/tuio2/alv"); - - for(std::list::iterator tobj = tobjList.begin();tobj!= tobjList.end(); tobj++) - (*oscPacket) << (int32)(*tobj)->getSessionID(); - - (*oscPacket) << osc::EndMessage; - //int after = oscPacket->Capacity()-oscPacket->Size(); - //printf("ALV_MESSAGE_SIZE: %i\n",before-after); - - (*oscPacket) << osc::EndBundle; - deliverOscPacket( oscPacket ); -} - - diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioSource.h b/modules/touch/ext/libTUIO2/TUIO2/TuioSource.h deleted file mode 100644 index 2bf5593a07..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioSource.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. - */ - -#ifndef INCLUDED_TUIOSOURCE_H -#define INCLUDED_TUIOSOURCE_H - -#include -#include -#include -#include - -namespace TUIO2 { - - /** - * The TuioSource class encapsulates the meta data for the TUIO source attributes provided in /tuio2/frm. - * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - - class LIBDECL TuioSource { - - protected: - /** - * The ID of the TUIO source - */ - unsigned int source_id; - /** - * The name of the TUIO source - */ - std::string source_name; - /** - * The instance of the TUIO source - */ - unsigned int source_instance; - /** - * The address of the TUIO source - */ - std::string source_address; - /** - * The encoded sensor dimension - */ - unsigned int dimension; - /** - * The TuioTime of the last frame - */ - TuioTime frameTime; - - public: - - /** - * Sets the ID, name and address of the TUIO source - */ - TuioSource() { - source_id = 0; - source_name = "default"; - source_instance = 0; - source_address = "localhost"; - dimension = 0; - }; - - /** - * Sets the ID, name and address of the TUIO source - * - * @param src_name the name of the TUIO source - */ - TuioSource(std::string src_name) { - source_id = 0; - source_name = src_name; - source_instance = 0; - source_address = "localhost"; - dimension = 0; - }; - - /** - * Sets the ID, name and address of the TUIO source - * - * @param src_name the name of the TUIO source - */ - TuioSource(unsigned int sid, std::string src_string, unsigned int dim) { - source_id = sid; - setSourceString(src_string); - setDimension(dim); - }; - - /** - * Sets the ID, name and address of the TUIO source - * - * @param src_name the name of the TUIO source - * @param src_inst the instance of the TUIO source - * @param src_addr the address of the TUIO source - */ - TuioSource(std::string src_name, unsigned int src_inst, std::string src_addr) { - source_id = 0; - source_name = src_name; - source_instance = src_inst; - source_address = src_addr; - }; - - /** - * Sets the ID, name and address of the TUIO source - * - * @param src_id the ID of the TUIO source - * @param src_name the name of the TUIO source - * @param src_inst the instance of the TUIO source - * @param src_addr the address of the TUIO source - */ - TuioSource(unsigned int src_id, std::string src_name, unsigned int src_inst, std::string src_addr) { - source_id = src_id; - source_name = src_name; - source_instance = src_inst; - source_address = src_addr; - }; - - ~TuioSource() {}; - - void setSourceString(std::string src_string) { - - if (src_string.length()==0) return; - char *data = strdup(src_string.c_str()); - - char *name_inst = strtok(data, "@"); - - char *addr = strtok(NULL, "@"); - if (addr!=NULL) source_address = std::string(addr); - else source_address = (char*)"0x7F000001"; - - char *name = strtok(name_inst, ":"); - source_name = std::string(name); - - char *inst = strtok(NULL, ":"); - if (inst!=NULL) source_instance = atoi(inst); - else source_instance = 0; - } - - void setSourceString(unsigned int src_id, std::string src_string) { - - source_id = src_id; - setSourceString(src_string); - } - - std::string getSourceString() { - - std::stringstream src_stream; - src_stream << source_name << ":" << source_instance << "@" << source_address; - return src_stream.str(); - } - - /** - * Returns the ID of the TUIO source - */ - unsigned int getSourceID() { return source_id; } - - /** - * Returns the name of the TUIO source - */ - const char* getSourceName() { return source_name.c_str(); } - - /** - * Returns the instance of the TUIO source - */ - unsigned int getSourceInstance() { return source_instance; } - - /** - * Returns the address of the TUIO source - */ - const char* getSourceAddress() { return source_address.c_str(); } - - /** - * Encodes the sensor dimension - * @param w the sensor width - * @param h the sensor height - */ - void setDimension(unsigned short w, unsigned short h) { - dimension = w << 16 | h; - } - - /** - * Sets the encoded sensor dimension - * @param d the sensor dimension - */ - void setDimension(unsigned int d) { - dimension = d; - } - - /** - * Returns the encoded sensor dimension - * @return the encoded sensor dimension - */ - unsigned int getDimension() { - return dimension; - } - - /** - * Returns the decoded sensor width - * @return the decoded sensor width - */ - unsigned short getWidth() { - unsigned short width = dimension >> 16; - return width; - } - - /** - * Returns the decoded sensor height - * @return the decoded sensor height - */ - unsigned short getHeight() { - unsigned short height = dimension & 0x0000FFFF; - return height; - } - - /** - * Sets the last frame time - * @param ttime the TuioTime of the last frame - */ - void setFrameTime(TuioTime ttime) { - frameTime = ttime; - } - - /** - * Returns the last frame time - * @return the TuioTime of the last frame - */ - TuioTime getFrameTime() { - return frameTime; - } - }; -} -#endif // INCLUDED_TUIOSOURCE_H diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp deleted file mode 100644 index 4447c3a227..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioSymbol.h" - -using namespace TUIO2; - -TuioSymbol::TuioSymbol (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data):TuioComponent(ttime,tobj,0,0,0) { - currentTime = ttime; - startTime = currentTime; - type_id = ti; - user_id = ui; - symbol_id = sym; - symbol_type = std::string(type); - symbol_data = std::string(data); - state = TUIO_ADDED; -} - -TuioSymbol::TuioSymbol (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data):TuioComponent(tobj,0,0,0) { - currentTime = TuioTime::getSystemTime(); - startTime = currentTime; - type_id = ti; - user_id = ui; - symbol_id = sym; - symbol_type = std::string(type); - symbol_data = std::string(data); - state = TUIO_ADDED; -} - -TuioSymbol::TuioSymbol (TuioSymbol *tsym):TuioComponent(tsym->getTuioTime(),tsym->getContainingTuioObject(),0,0,0) { - currentTime = TuioTime::getSystemTime(); - startTime = currentTime; - session_id = tsym->getSessionID(); - type_id = tsym->getTypeID(); - user_id = tsym->getUserID(); - symbol_id = tsym->getSymbolID(); - symbol_type = tsym->getSymbolType(); - symbol_data = tsym->getSymbolData(); - state = TUIO_ADDED; -} - -unsigned int TuioSymbol::getSymbolID() const { - return symbol_id; -} - -unsigned short TuioSymbol::getTypeID() const { - return type_id; -} - -unsigned short TuioSymbol::getUserID() const { - return user_id; -} - -unsigned int TuioSymbol::getTypeUserID() const { - int tu_id = user_id << 16 | type_id; - return tu_id; -} - -void TuioSymbol::setTypeUserID(unsigned int tu_id) { - user_id = tu_id >> 16; - type_id = tu_id & 0x0000FFFF; -} - -const char* TuioSymbol::getSymbolType() const { - return symbol_type.c_str(); -} - -const char* TuioSymbol::getSymbolData() const { - return symbol_data.c_str(); -} - -void TuioSymbol::update(TuioTime ttime) { - TuioComponent::update(ttime,0,0); - -} - diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h b/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h deleted file mode 100644 index d66e32845d..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioSymbol.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOSYMBOL_H -#define INCLUDED_TUIOSYMBOL_H -//#pragma clang diagnostic ignored "-Woverloaded-virtual" - -#include "TuioTime.h" -#include "TuioComponent.h" -#include - -namespace TUIO2 { - - /** - * The TuioSymbol class encapsulates /tuio2/sym TUIO symbol. - * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - class LIBDECL TuioSymbol : public TuioComponent { - - protected: - /** - * The unique Session ID that is assigned to each TUIO tobj. - */ - unsigned int session_id; - /** - * The individual symbol ID number that is assigned to each TuioToken. - */ - unsigned int symbol_id; - /** - * The symbol type ID that is assigned to each TuioToken. - */ - unsigned short type_id; - /** - * The user ID that is assigned to each TuioToken. - */ - unsigned short user_id; - /** - * The symbol type descriptor - */ - std::string symbol_type; - /** - * The actual symbol data - */ - std::string symbol_data; - /** - * The time stamp of the last update represented as TuioTime (time since session start) - */ - TuioTime currentTime; - /** - * The creation time of this TuioPoint represented as TuioTime (time since session start) - */ - TuioTime startTime; - /** - * Reflects the current state of the TuioSymbol - */ - unsigned char state; - - public: - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, Type ID, User ID and Symbol ID as well as the Symbol type and data. - * - * @param ttime the TuioTime to assign - * @param tobj the TuioObject to assign - * @param ti the Type ID to assign - * @param ui the User ID to assign - * @param sym the Symbol ID to assign - * @param type the symbol type descriptor - * @param data the symbol data to assign - */ - TuioSymbol (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data); - - /** - * This constructor assigns the provided Session ID, Type ID, User ID and Symbol ID - * as well as the Symbol type and data. - * - * @param tobj the TuioObject to assign - * @param ti the Type ID to assign - * @param ui the User ID to assign - * @param sym the Symbol ID to assign - * @param type the symbol type descriptor - * @param data the symbol data to assign - */ - TuioSymbol (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, const char *type, const char *data); - - /** - * This constructor takes a TuioSymbol argument and sets its attributes - * to the ones of the provided TuioSymbol. - * - * @param tsym the TuioSymbol to assign - */ - TuioSymbol (TuioSymbol *tsym); - - /** - * Returns the Symbol ID of this TuioSymbol. - * @return the Symbol ID of this TuioSymbol - */ - unsigned int getSymbolID() const; - - /** - * Returns the Type ID of this TuioSymbol. - * @return the Type ID of this TuioSymbol - */ - unsigned short getTypeID() const; - - /** - * Returns the User ID of this TuioSymbol. - * @return the User ID of this TuioSymbol - */ - unsigned short getUserID() const; - - /** - * Returns the encoded Type & User ID of this TuioSymbol. - * @return the encoded Type & User ID of this TuioSymbol - */ - unsigned int getTypeUserID() const; - - /** - * Decodes and assigns the Type & User ID to this TuioSymbol. - * @param tu_id the encoded Type & User ID of this TuioSymbol - */ - void setTypeUserID(unsigned int tu_id); - - /** - * Returns the Type string of this TuioSymbol. - * @return the Type string of this TuioSymbol - */ - const char* getSymbolType() const; - - /** - * Returns the actual data of this TuioSymbol. - * @return the actual data of this TuioSymbol - */ - const char* getSymbolData() const; - - - void update(TuioTime ttime); - /*void update(TuioTime ttime, float xp, float yp); - void update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma); - void update (TuioSymbol *tsym);*/ - }; -} -#endif diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp b/modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp deleted file mode 100644 index 375c80e792..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioToken.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioToken.h" - -using namespace TUIO2; - -TuioToken::TuioToken (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a):TuioComponent(ttime, tobj, xp, yp,a) { - type_id = ti; - user_id = ui; - symbol_id = sym; -} - -TuioToken::TuioToken (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a):TuioComponent(tobj, xp, yp, a) { - type_id = ti; - user_id = ui; - symbol_id = sym; -} - -TuioToken::TuioToken (TuioObject *tobj, unsigned int sym, float xp, float yp, float a):TuioComponent(tobj, xp, yp, a) { - type_id = 0; - user_id = 0; - symbol_id = sym; -} - -TuioToken::TuioToken (TuioToken *ttok):TuioComponent(ttok) { - symbol_id = ttok->getSymbolID(); -} - -void TuioToken::stop (TuioTime ttime) { - update(ttime,xpos,ypos,angle); -} - -unsigned int TuioToken::getSymbolID() const{ - return symbol_id; -} - -unsigned short TuioToken::getTypeID() const{ - return type_id; -}; - -unsigned short TuioToken::getUserID() const{ - return user_id; -}; - -unsigned int TuioToken::getTypeUserID() const { - int tu_id = user_id << 16 | type_id; - return tu_id; -} - -void TuioToken::setTypeUserID(unsigned int tu_id) { - user_id = tu_id >> 16; - type_id = tu_id & 0x0000FFFF; -} diff --git a/modules/touch/ext/libTUIO2/TUIO2/TuioToken.h b/modules/touch/ext/libTUIO2/TUIO2/TuioToken.h deleted file mode 100644 index c6b01a0816..0000000000 --- a/modules/touch/ext/libTUIO2/TUIO2/TuioToken.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - TUIO2 C++ Library - Copyright (c) 2009-2014 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOTOKEN_H -#define INCLUDED_TUIOTOKEN_H - -#include "TuioComponent.h" - -namespace TUIO2 { - - /** - * The TuioToken class encapsulates /tuio2/tok TUIO tokens. - * - * @author Martin Kaltenbrunner - * @version 2.0.a0 - */ - class LIBDECL TuioToken: public TuioComponent { - - protected: - /** - * The individual symbol ID number that is assigned to each TuioToken. - */ - unsigned int symbol_id; - /** - * The symbol type ID that is assigned to each TuioToken. - */ - unsigned short type_id; - /** - * The user ID that is assigned to each TuioToken. - */ - unsigned short user_id; - - public: - using TuioComponent::update; - - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, Symbol ID, X and Y coordinate and angle to the newly created TuioToken. - * - * @param ttime the TuioTime to assign - * @param tobj the TuioObject to assign - * @param ti the Type ID to assign - * @param ui the User ID to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - TuioToken (TuioTime ttime, TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a); - - /** - * This constructor takes the provided Session ID, Symbol ID, X and Y coordinate - * and angle, and assigs these values to the newly created TuioToken. - * - * @param tobj the TuioObject to assign - * @param ti the Type ID to assign - * @param ui the User ID to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - TuioToken (TuioObject *tobj, unsigned short ti, unsigned short ui, unsigned int sym, float xp, float yp, float a); - - /** - * This constructor takes the provided Session ID, Symbol ID, X and Y coordinate - * and angle, and assigs these values to the newly created TuioToken. - * - * @param tobj the TuioObject to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - TuioToken (TuioObject *tobj, unsigned int sym, float xp, float yp, float a); - - /** - * This constructor takes the atttibutes of the provided TuioToken - * and assigs these values to the newly created TuioToken. - * - * @param ttok the TuioToken to assign - */ - TuioToken (TuioToken *ttok); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioToken() {}; - - /** - * This method is used to calculate the speed and acceleration values of a - * TuioToken with unchanged position and angle. - */ - void stop (TuioTime ttime); - - /** - * Takes the atttibutes of the provided TuioToken - * and assigs these values to this TuioToken. - * The TuioTime time stamp of this TuioToken remains unchanged. - * - * @param ttok the TuioToken to assign - */ - void update (TuioToken *ttok); - - /** - * Returns the symbol ID of this TuioToken. - * @return the symbol ID of this TuioToken - */ - unsigned int getSymbolID() const; - - /** - * Returns the Type ID of this TuioToken. - * @return the Type ID of this TuioToken - */ - unsigned short getTypeID() const; - - /** - * Returns the User ID of this TuioToken. - * @return the User ID of this TuioToken - */ - unsigned short getUserID() const; - - /** - * Returns the encoded Type & User ID of this TuioToken. - * @return the encoded Type & User ID of this TuioToken - */ - unsigned int getTypeUserID() const; - - /** - * Decodes and assigns the Type & User ID to this TuioToken. - * @param tu_id the encoded Type & User ID of this TuioToken - */ - void setTypeUserID(unsigned int tu_id); - }; -} -#endif diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index e356b5d5ab..93d5e19a6d 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -25,15 +25,16 @@ #ifndef __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__ #define __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__ -#include -#include -#include -#include +#include +#include +#include +#include +#include "glm/glm.hpp" #include #include #include -using namespace TUIO2; +using namespace TUIO; class TuioEar : public TuioListener { @@ -45,12 +46,21 @@ class TuioEar : public TuioListener { delete _oscReceiver; } - void tuioAdd(TuioObject *tobj); - void tuioUpdate(TuioObject *tobj); - void tuioRemove(TuioObject *tobj); - void tuioRefresh(TuioTime frameTime); + void addTuioObject(TuioObject *tobj); + void updateTuioObject(TuioObject *tobj); + void removeTuioObject(TuioObject *tobj); - std::vector getInput(); + void addTuioCursor(TuioCursor *tcur); + void updateTuioCursor(TuioCursor *tcur); + void removeTuioCursor(TuioCursor *tcur); + + void addTuioBlob(TuioBlob *tblb); + void updateTuioBlob(TuioBlob *tblb); + void removeTuioBlob(TuioBlob *tblb); + + void refresh(TuioTime frameTime); + + std::vector getInput(); void clearInput(); void unlock() { _mx.unlock(); }; @@ -58,7 +68,7 @@ class TuioEar : public TuioListener { TuioClient *_tuioClient; OscReceiver *_oscReceiver; - std::vector _list; + std::vector _list; std::mutex _mx; }; diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index fef96aacb7..8dc8aa58e5 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -39,55 +39,70 @@ namespace { const std::string _loggerCat = "TuioEar"; } -void TuioEar::tuioAdd(TuioObject *tobj) { - if (tobj->containsNewTuioPointer()) { - _mx.lock(); - _list.push_back(tobj); +void TuioEar::addTuioObject(TuioObject *tobj) { + //std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; +} - //LINFO("add ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); - } - if (tobj->containsNewTuioToken()) LINFO("add tok " << tobj->getTuioToken()->getSessionID() << "\n"); - if(tobj->containsNewTuioBounds()) LINFO("add bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); - if(tobj->containsNewTuioSymbol()) LINFO("add sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); - //std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; +void TuioEar::updateTuioObject(TuioObject *tobj) { + //std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() + //<< " " << tobj->getMotionSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; +} + +void TuioEar::removeTuioObject(TuioObject *tobj) { + //std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ")" << std::endl; +} + +void TuioEar::addTuioCursor(TuioCursor *tcur) { + _mx.lock(); + _list.push_back(new TuioCursor(tcur)); _mx.unlock(); + + //LINFO("add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ") " << tcur->getX() << " " << tcur->getY() << " " << tobj->getY() << ", size: " << _list.size() << "\n"); + //std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ") " << tcur->getX() << " " << tcur->getY() << ", size: " << _list.size() << "\n"; } -void TuioEar::tuioUpdate(TuioObject *tobj) { - if (tobj->containsTuioPointer()) { - _mx.lock(); - _list.push_back(tobj); - - //LINFO("set ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); - } - if (tobj->containsTuioToken()) LINFO("set tok " << tobj->getTuioToken()->getSessionID() << "\n"); - if (tobj->containsTuioBounds()) LINFO("set bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); - if (tobj->containsTuioSymbol()) LINFO("set sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); - //std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << " " << tobj->getMotionSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; +void TuioEar::updateTuioCursor(TuioCursor *tcur) { + _mx.lock(); + _list.push_back(new TuioCursor(tcur)); _mx.unlock(); + + //LINFO("set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << ", size: " << _list.size() << "\n"); + //std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ") " << tcur->getX() << " " << tcur->getY() + //<< " " << tcur->getMotionSpeed() << " " << tcur->getMotionAccel() << " " << ", size: " << _list.size() << "\n"; } -void TuioEar::tuioRemove(TuioObject *tobj) { - if (tobj->containsTuioPointer()) { - LINFO("del ptr " << tobj->getTuioPointer()->getSessionID() << ", size: " << _list.size() << "\n"); - } - if (tobj->containsTuioToken()) LINFO("del tok " << tobj->getTuioToken()->getSessionID() << "\n"); - if (tobj->containsTuioBounds()) LINFO("del bnd " << tobj->getTuioBounds()->getSessionID() << "\n"); - if (tobj->containsTuioSymbol()) LINFO("del sym " << tobj->getTuioSymbol()->getSessionID() << "\n"); - //std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/"<< tobj->getTuioSourceID() << ")" << std::endl; +void TuioEar::removeTuioCursor(TuioCursor *tcur) { + //std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ")" << std::endl; } -void TuioEar::tuioRefresh(TuioTime frameTime) { - //LINFO("refresh " << frameTime.getFrameID() << " "<< frameTime.getTotalMilliseconds() << "\n"); +void TuioEar::addTuioBlob(TuioBlob *tblb) { + std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; } -std::vector TuioEar::getInput() { +void TuioEar::updateTuioBlob(TuioBlob *tblb) { + std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() + << " " << tblb->getMotionSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel() << " " << tblb->getRotationAccel() << std::endl; +} + +void TuioEar::removeTuioBlob(TuioBlob *tblb) { + std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ")" << std::endl; +} + + +void TuioEar::refresh(TuioTime frameTime) { + //LINFO("refresh " << frameTime.getTotalMilliseconds() << "\n"); // about every 15ms on TuioPad app +} + +std::vector TuioEar::getInput() { _mx.lock(); return _list; } void TuioEar::clearInput() { _mx.lock(); + for (auto &&j : _list) { + delete j; + } _list.clear(); _mx.unlock(); } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index e585919812..5189a1ffb4 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -67,21 +67,25 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw OpenSpaceEngine::CallbackOption::PreSync, [&]() { - std::vector list = ear->getInput(); - std::vector group; + std::vector list = ear->getInput(); + std::vector group; glm::vec2 centroid; ear->unlock(); - std::string s = ""; + //print list for debugging + std::string s = ""; const std::string _loggerCat = "TouchModule"; std::ostringstream os; for (auto &&j : list) { - os << " (" << j->getTuioPointer()->getX() << "," << j->getTuioPointer()->getY() << ") "; + os << " (" << j->getX() << "," << j->getY() << ") "; } if (list.size() > 0) LINFO("List size: " << list.size() << os.str() << "\n"); os.clear(); + + ear->clearInput(); + /* // step through the list (from the start) and find each unique id TuioObject for (auto &&i : list) { bool sameId = false; @@ -104,7 +108,7 @@ TouchModule::TouchModule() } - } + }*/ //if (centroid.x + centroid.y != 0.0f) //LINFO("List size: " << list.size() << ", Centroid: (" << centroid.x << ", " << centroid.y << ")\n"); @@ -117,7 +121,7 @@ TouchModule::TouchModule() [&]() { WindowWrapper& wrapper = OsEng.windowWrapper(); if (OsEng.isMaster() && wrapper.isRegularRendering()) { - ear->clearInput(); + } } ); From 49ca8eb2aa00bd0d6ff511bd1e73b49f16670676 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 22 Feb 2017 15:41:52 -0700 Subject: [PATCH 005/192] save input safely between frames with cursor->getPath() and clear list (& refrence path) after process to not lose any information --- modules/touch/include/TuioEar.h | 8 +-- modules/touch/src/TuioEar.cpp | 82 ++++++++++++++++++++++------- modules/touch/touchmodule.cpp | 61 ++++++++++----------- src/interaction/interactionmode.cpp | 2 +- 4 files changed, 97 insertions(+), 56 deletions(-) diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index 93d5e19a6d..ffee968e3a 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -60,15 +60,17 @@ class TuioEar : public TuioListener { void refresh(TuioTime frameTime); - std::vector getInput(); + TuioTime getLastProcessedTime(int id); + std::vector getInput(); void clearInput(); - void unlock() { _mx.unlock(); }; private: TuioClient *_tuioClient; OscReceiver *_oscReceiver; - std::vector _list; + std::vector _list; + std::vector _removeList; + std::vector> _processedPath; std::mutex _mx; }; diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 8dc8aa58e5..7704b348da 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -34,6 +34,7 @@ #include #include +#include namespace { const std::string _loggerCat = "TuioEar"; @@ -53,26 +54,49 @@ void TuioEar::removeTuioObject(TuioObject *tobj) { } void TuioEar::addTuioCursor(TuioCursor *tcur) { - _mx.lock(); - _list.push_back(new TuioCursor(tcur)); - _mx.unlock(); + _mx.lock(); - //LINFO("add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ") " << tcur->getX() << " " << tcur->getY() << " " << tobj->getY() << ", size: " << _list.size() << "\n"); - //std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ") " << tcur->getX() << " " << tcur->getY() << ", size: " << _list.size() << "\n"; + // find same id in _list if it exists in _removeList (new input with same ID as a previously stored) + int i = tcur->getSessionID(); + auto foundID = std::find_if( + _removeList.begin(), + _removeList.end(), + [&i](int id) { return id == i; }); + + // if found, remove id from _removeList and update, otherwise add new id to list + if (foundID != _removeList.end()) { + std::find_if( + _list.begin(), + _list.end(), + [&i](const TuioCursor& cursor) { + return cursor.getSessionID() == i; + })->update(tcur); + _removeList.erase(foundID); + } + else + _list.push_back(TuioCursor(*tcur)); + + _mx.unlock(); } void TuioEar::updateTuioCursor(TuioCursor *tcur) { _mx.lock(); - _list.push_back(new TuioCursor(tcur)); + int i = tcur->getSessionID(); + std::find_if( + _list.begin(), + _list.end(), + [&i](const TuioCursor& cursor) { + return cursor.getSessionID() == i; + })->update(tcur); _mx.unlock(); - - //LINFO("set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << ", size: " << _list.size() << "\n"); - //std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ") " << tcur->getX() << " " << tcur->getY() - //<< " " << tcur->getMotionSpeed() << " " << tcur->getMotionAccel() << " " << ", size: " << _list.size() << "\n"; } +// save id to be removed and remove it in clearInput void TuioEar::removeTuioCursor(TuioCursor *tcur) { - //std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << "/" << tcur->getTuioSourceID() << ")" << std::endl; + _mx.lock(); + _removeList.push_back(tcur->getSessionID()); + //LINFO("To be removed: " << _removeFromList.size() << "\n"); + _mx.unlock(); } void TuioEar::addTuioBlob(TuioBlob *tblb) { @@ -88,22 +112,44 @@ void TuioEar::removeTuioBlob(TuioBlob *tblb) { std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ")" << std::endl; } - void TuioEar::refresh(TuioTime frameTime) { //LINFO("refresh " << frameTime.getTotalMilliseconds() << "\n"); // about every 15ms on TuioPad app } -std::vector TuioEar::getInput() { - _mx.lock(); +TuioTime TuioEar::getLastProcessedTime(int id) { + return std::find_if( + _processedPath.begin(), + _processedPath.end(), + [&id](std::pair t) { return id = t.first; } + )->second; +} + +std::vector TuioEar::getInput() { + std::lock_guard lock(_mx); + _processedPath.clear(); + for (const TuioCursor& c : _list) + _processedPath.push_back(std::make_pair(c.getSessionID(), c.getTuioTime())); return _list; } void TuioEar::clearInput() { _mx.lock(); - for (auto &&j : _list) { - delete j; - } - _list.clear(); + _list.erase( + std::remove_if( + _list.begin(), + _list.end(), + [this](const TuioCursor& cursor) { + return std::find_if( + _removeList.begin(), + _removeList.end(), + [&cursor](int id) { + return cursor.getSessionID() == id; + } + ) != _removeList.end(); + }), + _list.end() + ); + _removeList.clear(); _mx.unlock(); } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 5189a1ffb4..f949c380f8 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -39,6 +39,12 @@ #include #include #include +#include // std::this_thread::sleep_for +#include // std::chrono::seconds + +namespace { + const std::string _loggerCat = "TouchModule"; +} namespace openspace { @@ -67,52 +73,39 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw OpenSpaceEngine::CallbackOption::PreSync, [&]() { - std::vector list = ear->getInput(); - std::vector group; + //std::this_thread::sleep_for(std::chrono::seconds(1)); + std::vector list = ear->getInput(); + ear->clearInput(); glm::vec2 centroid; - ear->unlock(); + //print list for debugging std::string s = ""; - const std::string _loggerCat = "TouchModule"; std::ostringstream os; - for (auto &&j : list) { - os << " (" << j->getX() << "," << j->getY() << ") "; + for (const TuioCursor &j : list) { + + os << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << ") "; } if (list.size() > 0) - LINFO("List size: " << list.size() << os.str() << "\n"); + LINFO("List size: " << list.size() << ", Id: " << os.str() << "\n"); os.clear(); - - - ear->clearInput(); /* - // step through the list (from the start) and find each unique id TuioObject - for (auto &&i : list) { - bool sameId = false; + // calculate centroid if multipleID + if (list.size() > 1) { centroid = glm::vec2(0.0f, 0.0f); - if (i->containsTuioPointer()) { // sanity check - int id = i->getSessionID(); - for (auto &&j : group) // change to lambda/find function - if (j->getSessionID() == id) - sameId = true; // step out of for - if (sameId) { // calculate a centroid - for (auto &&j : group) { - centroid.x += j->getTuioPointer()->getX(); - centroid.y += j->getTuioPointer()->getY(); - } - centroid.x /= group.size(); - centroid.y /= group.size(); - } - else - group.push_back(i); - - + for (auto &&i : list) { + centroid.x += i->getX(); + centroid.y += i->getY(); } - }*/ + centroid.x /= list.size(); + centroid.y /= list.size(); + + //LINFO("List size: " << list.size() << ", Centroid: (" << centroid.x << ", " << centroid.y << ")" << "\n"); + } + */ - //if (centroid.x + centroid.y != 0.0f) - //LINFO("List size: " << list.size() << ", Centroid: (" << centroid.x << ", " << centroid.y << ")\n"); - // group + glm::mat4 t; + //OsEng.interactionHandler().camera()->rotate(); } ); diff --git a/src/interaction/interactionmode.cpp b/src/interaction/interactionmode.cpp index d6d18bed88..9b6e88822a 100644 --- a/src/interaction/interactionmode.cpp +++ b/src/interaction/interactionmode.cpp @@ -201,7 +201,7 @@ Interpolator& InteractionMode::rotateToFocusNodeInterpolator() { // KeyframeInteractionMode -KeyframeInteractionMode::KeyframeInteractionMode(){ +KeyframeInteractionMode::KeyframeInteractionMode() { } From a2ff460d78cff4cc94b62974b4b8b79ed3d86453 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 22 Feb 2017 18:52:11 -0700 Subject: [PATCH 006/192] small fix on processedList to lastList, TuioTime still not a good way to compare different timestamped inputs --- modules/touch/include/TuioEar.h | 2 -- modules/touch/src/TuioEar.cpp | 13 +------------ modules/touch/touchmodule.cpp | 23 +++++++++++++++++++---- modules/touch/touchmodule.h | 2 ++ 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index ffee968e3a..7597ae8c3a 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -60,7 +60,6 @@ class TuioEar : public TuioListener { void refresh(TuioTime frameTime); - TuioTime getLastProcessedTime(int id); std::vector getInput(); void clearInput(); @@ -70,7 +69,6 @@ class TuioEar : public TuioListener { std::vector _list; std::vector _removeList; - std::vector> _processedPath; std::mutex _mx; }; diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 7704b348da..0755dfe3fb 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -58,7 +58,7 @@ void TuioEar::addTuioCursor(TuioCursor *tcur) { // find same id in _list if it exists in _removeList (new input with same ID as a previously stored) int i = tcur->getSessionID(); - auto foundID = std::find_if( + std::vector::iterator foundID = std::find_if( _removeList.begin(), _removeList.end(), [&i](int id) { return id == i; }); @@ -116,19 +116,8 @@ void TuioEar::refresh(TuioTime frameTime) { //LINFO("refresh " << frameTime.getTotalMilliseconds() << "\n"); // about every 15ms on TuioPad app } -TuioTime TuioEar::getLastProcessedTime(int id) { - return std::find_if( - _processedPath.begin(), - _processedPath.end(), - [&id](std::pair t) { return id = t.first; } - )->second; -} - std::vector TuioEar::getInput() { std::lock_guard lock(_mx); - _processedPath.clear(); - for (const TuioCursor& c : _list) - _processedPath.push_back(std::make_pair(c.getSessionID(), c.getTuioTime())); return _list; } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index f949c380f8..b28d8231f7 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -74,7 +74,7 @@ TouchModule::TouchModule() OpenSpaceEngine::CallbackOption::PreSync, [&]() { //std::this_thread::sleep_for(std::chrono::seconds(1)); - std::vector list = ear->getInput(); + list = ear->getInput(); ear->clearInput(); glm::vec2 centroid; @@ -83,11 +83,23 @@ TouchModule::TouchModule() std::string s = ""; std::ostringstream os; for (const TuioCursor &j : list) { - - os << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << ") "; + + int count = 0; + std::list path = j.getPath(); + if (lastList.size() > 0 && list.size() > 0) { // sanity check + std::vector::iterator last = find_if( + lastList.begin(), + lastList.end(), + [&j](const TuioCursor& c) { return c.getSessionID() == j.getSessionID(); } + ); + if (last != lastList.end()) + (path.size() < 128) ? count = path.size() - last->getPath().size() : count = 1; // guess how many? all? + } + + os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count; } if (list.size() > 0) - LINFO("List size: " << list.size() << ", Id: " << os.str() << "\n"); + LINFO("List size: " << list.size() << os.str() << "\n"); os.clear(); /* // calculate centroid if multipleID @@ -105,7 +117,10 @@ TouchModule::TouchModule() */ glm::mat4 t; + //OsEng.interactionHandler().camera()->rotate(); + + lastList = list; } ); diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 7f14817d58..6601a6266b 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -35,6 +35,8 @@ public: TouchModule(); TuioEar *ear; + std::vector list; + std::vector lastList; }; } // namespace openspace From 1f147b6a3e8d8ff774b0842cbb7cfc432405c9c1 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 23 Feb 2017 13:39:37 -0700 Subject: [PATCH 007/192] comparison of with TuioTime to find new points since last frame now works --- modules/touch/touchmodule.cpp | 78 +++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index b28d8231f7..b9ed9627c5 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -73,53 +73,59 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw OpenSpaceEngine::CallbackOption::PreSync, [&]() { - //std::this_thread::sleep_for(std::chrono::seconds(1)); + std::this_thread::sleep_for(std::chrono::seconds(1)); list = ear->getInput(); ear->clearInput(); - glm::vec2 centroid; - - - //print list for debugging - std::string s = ""; - std::ostringstream os; - for (const TuioCursor &j : list) { - - int count = 0; - std::list path = j.getPath(); - if (lastList.size() > 0 && list.size() > 0) { // sanity check - std::vector::iterator last = find_if( + + if (list.size() > 0) { // sanity check, no need to process if no input + glm::vec2 centroid; + + //print list for debugging + std::ostringstream os; + for (const TuioCursor &j : list) { + int count = 0; + TuioTime lastTime; + std::list path = j.getPath(); + std::vector::iterator it = find_if( lastList.begin(), lastList.end(), [&j](const TuioCursor& c) { return c.getSessionID() == j.getSessionID(); } ); - if (last != lastList.end()) - (path.size() < 128) ? count = path.size() - last->getPath().size() : count = 1; // guess how many? all? + if (it != lastList.end()) // sanity check, if first element id wont be found in lastList + lastTime = it->getPath().back().getTuioTime(); + + // step through path and find where lastTime == c.getTuioTime() + std::list::iterator lastPoint = find_if( + path.begin(), + path.end(), + [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); + + for (; lastPoint != path.end(); ++lastPoint) // here we can access all elements that are to be processed + count++; + + os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count; } + LINFO("List size: " << list.size() << os.str() << "\n"); + os.clear(); + - os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count; - } - if (list.size() > 0) - LINFO("List size: " << list.size() << os.str() << "\n"); - os.clear(); - /* - // calculate centroid if multipleID - if (list.size() > 1) { - centroid = glm::vec2(0.0f, 0.0f); - for (auto &&i : list) { - centroid.x += i->getX(); - centroid.y += i->getY(); + // calculate centroid if multipleID + /*if (list.size() > 1) { + centroid = glm::vec2(0.0f, 0.0f); + for (auto &&i : list) { + centroid.x += i->getX(); + centroid.y += i->getY(); + } + centroid.x /= list.size(); + centroid.y /= list.size(); + + //LINFO("List size: " << list.size() << ", Centroid: (" << centroid.x << ", " << centroid.y << ")" << "\n"); } - centroid.x /= list.size(); - centroid.y /= list.size(); + */ - //LINFO("List size: " << list.size() << ", Centroid: (" << centroid.x << ", " << centroid.y << ")" << "\n"); + glm::mat4 t; + //OsEng.interactionHandler().camera()->rotate(); } - */ - - glm::mat4 t; - - //OsEng.interactionHandler().camera()->rotate(); - lastList = list; } ); From 89c985570cf17624be5a9ff5a735fed3071b7b8b Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 23 Feb 2017 20:34:18 -0700 Subject: [PATCH 008/192] crude solution to zoom works, figuring out how to rotate around a focusNode with touch input --- modules/touch/include/TuioEar.h | 7 ++- modules/touch/src/TuioEar.cpp | 3 +- modules/touch/touchmodule.cpp | 81 +++++++++++++++++++++------------ modules/touch/touchmodule.h | 1 + 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index 7597ae8c3a..ab3a73c78f 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -29,10 +29,15 @@ #include #include #include -#include "glm/glm.hpp" + +#include + #include #include #include +#include +#include +#include using namespace TUIO; diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 0755dfe3fb..ee7c282d07 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -33,8 +33,7 @@ #include #include -#include -#include + namespace { const std::string _loggerCat = "TuioEar"; diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index b9ed9627c5..7514ac4eec 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -33,8 +33,7 @@ #include #include -#include -#include +#include #include #include @@ -73,58 +72,84 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw OpenSpaceEngine::CallbackOption::PreSync, [&]() { - std::this_thread::sleep_for(std::chrono::seconds(1)); + //std::this_thread::sleep_for(std::chrono::seconds(1)); list = ear->getInput(); ear->clearInput(); - if (list.size() > 0) { // sanity check, no need to process if no input - glm::vec2 centroid; + Camera* cam = OsEng.interactionHandler().camera(); + glm::vec3 pos = cam->positionVec3(); + glm::vec3 focusDir = glm::normalize(glm::vec3(cam->focusPositionVec3()) - pos); - //print list for debugging - std::ostringstream os; - for (const TuioCursor &j : list) { - int count = 0; - TuioTime lastTime; + glm::vec2 centroid; + float distance = 0.0f; + float lastDistance = 0.0f; + float zoomFactor = 0.0f; + + if (list.size() > 0) { // sanity check, no need to process if no input + if (list.size() > 1 && list.size() == lastList.size()) { // calculate centroid if we have multiple IDs + centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](float x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](float y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + + + + + // ------- testing, should use more than just one point in lastList later on + distance = std::accumulate(list.begin(), list.end(), 0.0f, [¢roid](float d, const TuioCursor& c) { + return d + sqrt(pow(c.getX() - centroid.x,2) + pow(c.getY() - centroid.y,2)); + }); + lastDistance = std::accumulate(lastList.begin(), lastList.end(), 0.0f, [¢roid](float d, const TuioCursor& c) { + return d + sqrt(pow(c.getX() - centroid.x, 2) + pow(c.getY() - centroid.y, 2)); + }); + zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode + zoomFactor *= glm::distance(pos, glm::vec3(cam->focusPositionVec3())); + + std::cout << "Distance: " << distance << ", Last Distance: " << lastDistance << ", zoomFactor: " << zoomFactor + << ", pos: " << glm::to_string(pos) << ", focusDir: " << glm::to_string(focusDir) << "\n"; + + glm::vec3 newPos = pos + focusDir*zoomFactor; + cam->setPosition(newPos); + } + else if (lastList.size() > 0) { + // do new rotation + float x = list.at(0).getX() - lastList.at(0).getX(); + float y = list.at(0).getY() - lastList.at(0).getY(); + + glm::quat rot; + + //cam->rotate(rot); + } + // ---------------- + + + std::ostringstream os; // for debugging + + for (const TuioCursor &j : list) { // go through each item std::list path = j.getPath(); std::vector::iterator it = find_if( lastList.begin(), lastList.end(), [&j](const TuioCursor& c) { return c.getSessionID() == j.getSessionID(); } ); + TuioTime lastTime; if (it != lastList.end()) // sanity check, if first element id wont be found in lastList lastTime = it->getPath().back().getTuioTime(); - // step through path and find where lastTime == c.getTuioTime() std::list::iterator lastPoint = find_if( path.begin(), path.end(), [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); + int count = 0; for (; lastPoint != path.end(); ++lastPoint) // here we can access all elements that are to be processed count++; os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count; } - LINFO("List size: " << list.size() << os.str() << "\n"); + //LINFO("List size: " << list.size() << os.str() << "\n"); os.clear(); - - - // calculate centroid if multipleID - /*if (list.size() > 1) { - centroid = glm::vec2(0.0f, 0.0f); - for (auto &&i : list) { - centroid.x += i->getX(); - centroid.y += i->getY(); - } - centroid.x /= list.size(); - centroid.y /= list.size(); - - //LINFO("List size: " << list.size() << ", Centroid: (" << centroid.x << ", " << centroid.y << ")" << "\n"); - } - */ glm::mat4 t; - //OsEng.interactionHandler().camera()->rotate(); + } lastList = list; } diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 6601a6266b..5e2a4caa1b 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -37,6 +37,7 @@ public: TuioEar *ear; std::vector list; std::vector lastList; + }; } // namespace openspace From 36a7c62acbb5e6dbe9ff4d5f92080e0a7b4e0200 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Mon, 27 Feb 2017 18:59:47 -0700 Subject: [PATCH 009/192] attempt to make rotation work well --- modules/touch/touchmodule.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 7514ac4eec..e6c1d278ca 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -109,11 +109,27 @@ TouchModule::TouchModule() glm::vec3 newPos = pos + focusDir*zoomFactor; cam->setPosition(newPos); } - else if (lastList.size() > 0) { - // do new rotation + else if (lastList.size() > 0) { // do new rotation float x = list.at(0).getX() - lastList.at(0).getX(); float y = list.at(0).getY() - lastList.at(0).getY(); + // make x/y beteween -1 and 1 + //x = 2 * (x - 0.5); + //y = 2 * (y - 0.5); + // arcsin to get angles + float thetaX = std::max(5*acos(x), 1.0f); + float thetaY = std::max(5*asin(y), 1.0f); + // make rotation around right axis.. + + glm::vec3 lookDir = cam->viewDirectionWorldSpace(); + glm::vec3 lookUp = cam->lookUpVectorWorldSpace(); + glm::vec3 right = glm::cross(lookUp, lookDir); + glm::vec3 rotVec = glm::vec3(1.0, 0.0, 0.0); + glm::rotate(rotVec, thetaX, lookUp); + glm::rotate(rotVec, thetaY, right); + + //std::cout << "Coordinates: (" << x << ", " << y << "), Angles: (" << thetaX << ", " << thetaY << ")\n"; + std::cout << "Before rotation: " << glm::to_string(glm::vec3(1.0,0.0,0.0)) << ", After: " << glm::to_string(rotVec) << "\n"; glm::quat rot; //cam->rotate(rot); From 436d573c75549e5d7357a0f06d2dd4265e96f93f Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 2 Mar 2017 14:35:41 -0700 Subject: [PATCH 010/192] lastList is now a pair of id and the last frames TuioPoint. Makes check to only process if we get new input --- modules/touch/src/TuioEar.cpp | 2 +- modules/touch/touchmodule.cpp | 132 +++++++++++++++++++--------------- modules/touch/touchmodule.h | 8 ++- 3 files changed, 81 insertions(+), 61 deletions(-) diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index ee7c282d07..3eb92a4942 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -130,7 +130,7 @@ void TuioEar::clearInput() { return std::find_if( _removeList.begin(), _removeList.end(), - [&cursor](int id) { + [&cursor](int id) {\ return cursor.getSessionID() == id; } ) != _removeList.end(); diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index e6c1d278ca..99ddaabcd6 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -49,6 +49,42 @@ namespace openspace { TuioEar TouchModule::*ear; + + +bool TouchModule::gotNewInput() { + // Get new input from listener + list = ear->getInput(); + ear->clearInput(); + + // Erase old input id's that no longer exists + lastProcessed.erase( + std::remove_if( + lastProcessed.begin(), + lastProcessed.end(), + [this](const Point& point) { + return std::find_if( + list.begin(), + list.end(), + [&point](const TuioCursor& c) { + return point.first == c.getSessionID(); + } + ) == list.end(); }), + lastProcessed.end() + ); + + // Return true if we got new input + if (list.size() == lastProcessed.size() && list.size() > 0) { + for (Point& p : lastProcessed) { + std::vector::iterator foundID = find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); + if (p.second.getTuioTime() == foundID->getPath().back().getTuioTime()) + return false; + } + return true; + } + else + return false; +} + TouchModule::TouchModule() : OpenSpaceModule("Touch") { @@ -72,66 +108,42 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw OpenSpaceEngine::CallbackOption::PreSync, [&]() { - //std::this_thread::sleep_for(std::chrono::seconds(1)); - list = ear->getInput(); - ear->clearInput(); + if (OsEng.isMaster() && gotNewInput()) { + //std::this_thread::sleep_for(std::chrono::seconds(1)); - Camera* cam = OsEng.interactionHandler().camera(); - glm::vec3 pos = cam->positionVec3(); - glm::vec3 focusDir = glm::normalize(glm::vec3(cam->focusPositionVec3()) - pos); + Camera* cam = OsEng.interactionHandler().camera(); + glm::vec3 pos = cam->positionVec3(); + glm::vec3 focusDir = glm::normalize(glm::vec3(cam->focusPositionVec3()) - pos); - glm::vec2 centroid; - float distance = 0.0f; - float lastDistance = 0.0f; - float zoomFactor = 0.0f; + glm::vec2 centroid; + float distance = 0.0f; + float lastDistance = 0.0f; + float zoomFactor = 0.0f; - if (list.size() > 0) { // sanity check, no need to process if no input - if (list.size() > 1 && list.size() == lastList.size()) { // calculate centroid if we have multiple IDs + if (list.size() > 1) { // calculate centroid if we have multiple IDs centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](float x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](float y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - // ------- testing, should use more than just one point in lastList later on - distance = std::accumulate(list.begin(), list.end(), 0.0f, [¢roid](float d, const TuioCursor& c) { - return d + sqrt(pow(c.getX() - centroid.x,2) + pow(c.getY() - centroid.y,2)); - }); - lastDistance = std::accumulate(lastList.begin(), lastList.end(), 0.0f, [¢roid](float d, const TuioCursor& c) { + // ------- testing, should use more than just one point later on + distance = std::accumulate(list.begin(), list.end(), 0.0f, [¢roid](float d, const TuioCursor& c) { return d + sqrt(pow(c.getX() - centroid.x, 2) + pow(c.getY() - centroid.y, 2)); }); + lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [¢roid](float d, const Point& p) { + return d + sqrt(pow(p.second.getX() - centroid.x, 2) + pow(p.second.getY() - centroid.y, 2)); + }); zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode zoomFactor *= glm::distance(pos, glm::vec3(cam->focusPositionVec3())); - std::cout << "Distance: " << distance << ", Last Distance: " << lastDistance << ", zoomFactor: " << zoomFactor - << ", pos: " << glm::to_string(pos) << ", focusDir: " << glm::to_string(focusDir) << "\n"; + std::cout << "Distance: " << distance << ", Last Distance: " << lastDistance << ", zoomFactor: " << zoomFactor + << "\n"; glm::vec3 newPos = pos + focusDir*zoomFactor; cam->setPosition(newPos); } - else if (lastList.size() > 0) { // do new rotation - float x = list.at(0).getX() - lastList.at(0).getX(); - float y = list.at(0).getY() - lastList.at(0).getY(); - // make x/y beteween -1 and 1 - //x = 2 * (x - 0.5); - //y = 2 * (y - 0.5); - // arcsin to get angles - float thetaX = std::max(5*acos(x), 1.0f); - float thetaY = std::max(5*asin(y), 1.0f); - // make rotation around right axis.. - - glm::vec3 lookDir = cam->viewDirectionWorldSpace(); - glm::vec3 lookUp = cam->lookUpVectorWorldSpace(); - glm::vec3 right = glm::cross(lookUp, lookDir); - - glm::vec3 rotVec = glm::vec3(1.0, 0.0, 0.0); - glm::rotate(rotVec, thetaX, lookUp); - glm::rotate(rotVec, thetaY, right); - - //std::cout << "Coordinates: (" << x << ", " << y << "), Angles: (" << thetaX << ", " << thetaY << ")\n"; - std::cout << "Before rotation: " << glm::to_string(glm::vec3(1.0,0.0,0.0)) << ", After: " << glm::to_string(rotVec) << "\n"; - glm::quat rot; - + else { // do new rotation, work with spherical coordinates. Orbit it both position and rotation, check OrbitInteractionMode in interactionmode //cam->rotate(rot); } // ---------------- @@ -141,33 +153,35 @@ TouchModule::TouchModule() for (const TuioCursor &j : list) { // go through each item std::list path = j.getPath(); - std::vector::iterator it = find_if( - lastList.begin(), - lastList.end(), - [&j](const TuioCursor& c) { return c.getSessionID() == j.getSessionID(); } - ); - TuioTime lastTime; - if (it != lastList.end()) // sanity check, if first element id wont be found in lastList - lastTime = it->getPath().back().getTuioTime(); - + + TuioTime lastTime = find_if( + lastProcessed.begin(), + lastProcessed.end(), + [&j](const Point& p) { return p.first == j.getSessionID(); } + )->second.getTuioTime(); + std::list::iterator lastPoint = find_if( - path.begin(), - path.end(), - [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); - + path.begin(), + path.end(), + [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); + int count = 0; for (; lastPoint != path.end(); ++lastPoint) // here we can access all elements that are to be processed count++; os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count; + } - //LINFO("List size: " << list.size() << os.str() << "\n"); + LINFO("List size: " << list.size() << os.str() << "\n"); os.clear(); - glm::mat4 t; - } - lastList = list; + + // update lastProcessed + lastProcessed.clear(); + for (const TuioCursor& c : list) { + lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); + } } ); diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 5e2a4caa1b..f73fd4780d 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -28,15 +28,21 @@ #include #include +//using Point = std::vector::iterator; + +using Point = std::pair; + namespace openspace { class TouchModule : public OpenSpaceModule { public: TouchModule(); + bool gotNewInput(); + TuioEar *ear; std::vector list; - std::vector lastList; + std::vector lastProcessed; // contains an id and the TuioPoint that was processed last frame }; From dbc5f806f4167ae0be7a55c3c2176c8d368e9fe5 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 2 Mar 2017 15:57:36 -0700 Subject: [PATCH 011/192] isMaster no longer exists --- modules/touch/src/TuioEar.cpp | 2 +- modules/touch/touchmodule.cpp | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 3eb92a4942..ee7c282d07 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -130,7 +130,7 @@ void TuioEar::clearInput() { return std::find_if( _removeList.begin(), _removeList.end(), - [&cursor](int id) {\ + [&cursor](int id) { return cursor.getSessionID() == id; } ) != _removeList.end(); diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 99ddaabcd6..f3d73926ad 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -108,7 +108,7 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw OpenSpaceEngine::CallbackOption::PreSync, [&]() { - if (OsEng.isMaster() && gotNewInput()) { + if (gotNewInput()) { //std::this_thread::sleep_for(std::chrono::seconds(1)); Camera* cam = OsEng.interactionHandler().camera(); @@ -124,9 +124,6 @@ TouchModule::TouchModule() centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](float x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](float y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - - - // ------- testing, should use more than just one point later on distance = std::accumulate(list.begin(), list.end(), 0.0f, [¢roid](float d, const TuioCursor& c) { return d + sqrt(pow(c.getX() - centroid.x, 2) + pow(c.getY() - centroid.y, 2)); @@ -184,16 +181,6 @@ TouchModule::TouchModule() } } ); - - OsEng.registerModuleCallback( - OpenSpaceEngine::CallbackOption::PostDraw, - [&]() { - WindowWrapper& wrapper = OsEng.windowWrapper(); - if (OsEng.isMaster() && wrapper.isRegularRendering()) { - - } - } - ); } From aee044f652bd4a933e3aa22a17573c30684bdb11 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 2 Mar 2017 16:12:55 -0700 Subject: [PATCH 012/192] exclude cache from esri --- .gitignore | 3 +- data/scene/missions/juno/juno/juno.mod | 23 ++-- data/spice/naif0011.tls | 148 +++++++++++++++++++++++++ 3 files changed, 163 insertions(+), 11 deletions(-) create mode 100644 data/spice/naif0011.tls diff --git a/.gitignore b/.gitignore index 38d00d5e83..2db24ce1fb 100644 --- a/.gitignore +++ b/.gitignore @@ -120,4 +120,5 @@ data/spice/plu055.bsp data/spice/Rosetta data/spice/sat375.bsp data/scene/lodglobes/saturn/Launcher.config -data/scene/lodglobes/mars/test_stats \ No newline at end of file +data/scene/lodglobes/mars/test_stats +data/scene/lodglobes/saturn/GDAL_cache_ESRI_Imagery_World_2d/ \ No newline at end of file diff --git a/data/scene/missions/juno/juno/juno.mod b/data/scene/missions/juno/juno/juno.mod index c9e4cc56df..12c2d45131 100644 --- a/data/scene/missions/juno/juno/juno.mod +++ b/data/scene/missions/juno/juno/juno.mod @@ -126,16 +126,19 @@ return { Name = "JunoTrail", Parent = "JupiterBarycenter", Renderable = { - Type = "RenderableTrailTrajectory", - Translation = { - Type = "SpiceTranslation", - Body = "JUNO", - Observer = "JUPITER BARYCENTER" - }, - Color = { 0.70, 0.50, 0.20 }, - StartTime = "2016 JUN 28", - EndTime = "2016 APR 01", - SampleInterval = 3600 + Type = "RenderableTrail", + Body = "JUNO", + Frame = "GALACTIC", + Observer = "JUPITER BARYCENTER", + RGB = { 0.70,0.50,0.20 }, + TropicalOrbitPeriod = 394250.0, + EarthOrbitRatio = 4.5, + DayLength = 9.9259, + TimeStamps = false, + Textures = { + Type = "simple", + Color = "textures/glare_blue.png", + }, }, }, } diff --git a/data/spice/naif0011.tls b/data/spice/naif0011.tls new file mode 100644 index 0000000000..58fcbcbd7f --- /dev/null +++ b/data/spice/naif0011.tls @@ -0,0 +1,148 @@ +KPL/LSK + + +LEAPSECONDS KERNEL FILE +=========================================================================== + +Modifications: +-------------- + +2015, Jan. 5 NJB Modified file to account for the leapsecond that + will occur on June 30, 2015. + +2012, Jan. 5 NJB Modified file to account for the leapsecond that + will occur on June 30, 2012. + +2008, Jul. 7 NJB Modified file to account for the leapsecond that + will occur on December 31, 2008. + +2005, Aug. 3 NJB Modified file to account for the leapsecond that + will occur on December 31, 2005. + +1998, Jul 17 WLT Modified file to account for the leapsecond that + will occur on December 31, 1998. + +1997, Feb 22 WLT Modified file to account for the leapsecond that + will occur on June 30, 1997. + +1995, Dec 14 KSZ Corrected date of last leapsecond from 1-1-95 + to 1-1-96. + +1995, Oct 25 WLT Modified file to account for the leapsecond that + will occur on Dec 31, 1995. + +1994, Jun 16 WLT Modified file to account for the leapsecond on + June 30, 1994. + +1993, Feb. 22 CHA Modified file to account for the leapsecond on + June 30, 1993. + +1992, Mar. 6 HAN Modified file to account for the leapsecond on + June 30, 1992. + +1990, Oct. 8 HAN Modified file to account for the leapsecond on + Dec. 31, 1990. + + +Explanation: +------------ + +The contents of this file are used by the routine DELTET to compute the +time difference + +[1] DELTA_ET = ET - UTC + +the increment to be applied to UTC to give ET. + +The difference between UTC and TAI, + +[2] DELTA_AT = TAI - UTC + +is always an integral number of seconds. The value of DELTA_AT was 10 +seconds in January 1972, and increases by one each time a leap second +is declared. Combining [1] and [2] gives + +[3] DELTA_ET = ET - (TAI - DELTA_AT) + + = (ET - TAI) + DELTA_AT + +The difference (ET - TAI) is periodic, and is given by + +[4] ET - TAI = DELTA_T_A + K sin E + +where DELTA_T_A and K are constant, and E is the eccentric anomaly of the +heliocentric orbit of the Earth-Moon barycenter. Equation [4], which ignores +small-period fluctuations, is accurate to about 0.000030 seconds. + +The eccentric anomaly E is given by + +[5] E = M + EB sin M + +where M is the mean anomaly, which in turn is given by + +[6] M = M + M t + 0 1 + +where t is the number of ephemeris seconds past J2000. + +Thus, in order to compute DELTA_ET, the following items are necessary. + + DELTA_TA + K + EB + M0 + M1 + DELTA_AT after each leap second. + +The numbers, and the formulation, are taken from the following sources. + + 1) Moyer, T.D., Transformation from Proper Time on Earth to + Coordinate Time in Solar System Barycentric Space-Time Frame + of Reference, Parts 1 and 2, Celestial Mechanics 23 (1981), + 33-56 and 57-68. + + 2) Moyer, T.D., Effects of Conversion to the J2000 Astronomical + Reference System on Algorithms for Computing Time Differences + and Clock Rates, JPL IOM 314.5--942, 1 October 1985. + +The variable names used above are consistent with those used in the +Astronomical Almanac. + +\begindata + +DELTET/DELTA_T_A = 32.184 +DELTET/K = 1.657D-3 +DELTET/EB = 1.671D-2 +DELTET/M = ( 6.239996D0 1.99096871D-7 ) + +DELTET/DELTA_AT = ( 10, @1972-JAN-1 + 11, @1972-JUL-1 + 12, @1973-JAN-1 + 13, @1974-JAN-1 + 14, @1975-JAN-1 + 15, @1976-JAN-1 + 16, @1977-JAN-1 + 17, @1978-JAN-1 + 18, @1979-JAN-1 + 19, @1980-JAN-1 + 20, @1981-JUL-1 + 21, @1982-JUL-1 + 22, @1983-JUL-1 + 23, @1985-JUL-1 + 24, @1988-JAN-1 + 25, @1990-JAN-1 + 26, @1991-JAN-1 + 27, @1992-JUL-1 + 28, @1993-JUL-1 + 29, @1994-JUL-1 + 30, @1996-JAN-1 + 31, @1997-JUL-1 + 32, @1999-JAN-1 + 33, @2006-JAN-1 + 34, @2009-JAN-1 + 35, @2012-JUL-1 + 36, @2015-JUL-1 ) + +\begintext + + From 436da23cd26fd9920c7d7636f8249e5f0de058c8 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 7 Mar 2017 10:24:07 -0700 Subject: [PATCH 013/192] Include posix files in lubTUIO if its built on a UNIX unit. Small cleanup in touchmodule --- modules/touch/ext/libTUIO/CMakeLists.txt | 44 ++++++++++++++---------- modules/touch/touchmodule.cpp | 14 ++++---- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/modules/touch/ext/libTUIO/CMakeLists.txt b/modules/touch/ext/libTUIO/CMakeLists.txt index a1f97f67fa..4e9b44dbc6 100644 --- a/modules/touch/ext/libTUIO/CMakeLists.txt +++ b/modules/touch/ext/libTUIO/CMakeLists.txt @@ -2,7 +2,7 @@ # # # OpenSpace # # # -# Copyright (c) 2014-2016 # +# Copyright (c) 2014-2017 # # # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # # software and associated documentation files (the "Software"), to deal in the Software # @@ -25,43 +25,51 @@ project(libTUIO) message(STATUS "Generating libTUIO project") -add_library(libTUIO +set(TUIO_SOURCE ${PROJECT_SOURCE_DIR}/TUIO/WebSockSender.cpp ${PROJECT_SOURCE_DIR}/TUIO/UdpSender.cpp ${PROJECT_SOURCE_DIR}/TUIO/UdpReceiver.cpp - #${PROJECT_SOURCE_DIR}/TUIO2/TuioToken.cpp ${PROJECT_SOURCE_DIR}/TUIO/TuioTime.cpp - #${PROJECT_SOURCE_DIR}/TUIO2/TuioSymbol.cpp ${PROJECT_SOURCE_DIR}/TUIO/TuioServer.cpp - #${PROJECT_SOURCE_DIR}/TUIO2/TuioPointer.cpp ${PROJECT_SOURCE_DIR}/TUIO/TuioPoint.cpp ${PROJECT_SOURCE_DIR}/TUIO/TuioObject.cpp ${PROJECT_SOURCE_DIR}/TUIO/TuioManager.cpp ${PROJECT_SOURCE_DIR}/TUIO/TuioDispatcher.cpp - #${PROJECT_SOURCE_DIR}/TUIO2/TuioComponent.cpp - ${PROJECT_SOURCE_DIR}/TUIO/TuioCursor.cpp # - ${PROJECT_SOURCE_DIR}/TUIO/TuioContainer.cpp # + ${PROJECT_SOURCE_DIR}/TUIO/TuioCursor.cpp + ${PROJECT_SOURCE_DIR}/TUIO/TuioContainer.cpp ${PROJECT_SOURCE_DIR}/TUIO/TuioClient.cpp - #${PROJECT_SOURCE_DIR}/TUIO2/TuioBounds.cpp - ${PROJECT_SOURCE_DIR}/TUIO/TuioBlob.cpp # + ${PROJECT_SOURCE_DIR}/TUIO/TuioBlob.cpp ${PROJECT_SOURCE_DIR}/TUIO/TcpSender.cpp ${PROJECT_SOURCE_DIR}/TUIO/TcpReceiver.cpp ${PROJECT_SOURCE_DIR}/TUIO/OscReceiver.cpp - ${PROJECT_SOURCE_DIR}/TUIO/OneEuroFilter.cpp # + ${PROJECT_SOURCE_DIR}/TUIO/OneEuroFilter.cpp ${PROJECT_SOURCE_DIR}/TUIO/FlashSender.cpp ${PROJECT_SOURCE_DIR}/oscpack/ip/IpEndpointName.cpp - #if (WIN32) - ${PROJECT_SOURCE_DIR}/oscpack/ip/win32/NetworkingUtils.cpp - ${PROJECT_SOURCE_DIR}/oscpack/ip/win32/UdpSocket.cpp - #else (WIN32) - #${PROJECT_SOURCE_DIR}/oscpack/ip/posix/NetworkingUtils.cpp - #${PROJECT_SOURCE_DIR}/oscpack/ip/posix/UdpSocket.cpp - #endif () ${PROJECT_SOURCE_DIR}/oscpack/osc/OscTypes.cpp ${PROJECT_SOURCE_DIR}/oscpack/osc/OscReceivedElements.cpp ${PROJECT_SOURCE_DIR}/oscpack/osc/OscPrintReceivedElements.cpp ${PROJECT_SOURCE_DIR}/oscpack/osc/OscOutboundPacketStream.cpp ) + +if (WIN32) + set(TUIO_SOURCE + ${TUIO_SOURCE} + ${PROJECT_SOURCE_DIR}/oscpack/ip/win32/NetworkingUtils.cpp + ${PROJECT_SOURCE_DIR}/oscpack/ip/win32/UdpSocket.cpp + ) +endif () + +if (UNIX) + set(TUIO_SOURCE + ${TUIO_SOURCE} + ${PROJECT_SOURCE_DIR}/oscpack/ip/posix/NetworkingUtils.cpp + ${PROJECT_SOURCE_DIR}/oscpack/ip/posix/UdpSocket.cpp + ) +endif () + +add_library(libTUIO + ${TUIO_SOURCE} +) target_include_directories(libTUIO PUBLIC ${PROJECT_SOURCE_DIR}) \ No newline at end of file diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index f3d73926ad..5edb6ffbfb 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -69,16 +69,14 @@ bool TouchModule::gotNewInput() { return point.first == c.getSessionID(); } ) == list.end(); }), - lastProcessed.end() - ); + lastProcessed.end()); // Return true if we got new input if (list.size() == lastProcessed.size() && list.size() > 0) { - for (Point& p : lastProcessed) { - std::vector::iterator foundID = find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); - if (p.second.getTuioTime() == foundID->getPath().back().getTuioTime()) + for_each(lastProcessed.begin(), lastProcessed.end(), [this](Point& p) { + if (p.second.getTuioTime() == find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; })->getPath().back().getTuioTime()) return false; - } + }); return true; } else @@ -105,10 +103,10 @@ TouchModule::TouchModule() } ); - OsEng.registerModuleCallback( // maybe call ear->clearInput() here rather than postdraw + OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::PreSync, [&]() { - if (gotNewInput()) { + if (gotNewInput() && OsEng.windowWrapper().isMaster()) { //std::this_thread::sleep_for(std::chrono::seconds(1)); Camera* cam = OsEng.interactionHandler().camera(); From 1451d2685162aae5a3bba340ace86fde45d73cca Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 7 Mar 2017 10:48:22 -0700 Subject: [PATCH 014/192] Include right directories on posix files as well --- .../touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp | 2 +- modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp b/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp index 7f36605472..720abc207e 100644 --- a/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp +++ b/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp @@ -34,7 +34,7 @@ requested that these non-binding requests be included whenever the above license is reproduced. */ -#include "ip/NetworkingUtils.h" +#include "oscpack/ip/NetworkingUtils.h" #include #include diff --git a/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp b/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp index b8262fcc99..f0f1afbb78 100644 --- a/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp +++ b/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp @@ -34,7 +34,7 @@ requested that these non-binding requests be included whenever the above license is reproduced. */ -#include "ip/UdpSocket.h" +#include "oscpack/ip/UdpSocket.h" #include #include @@ -57,8 +57,8 @@ #include #include -#include "ip/PacketListener.h" -#include "ip/TimerListener.h" +#include "oscpack/ip/PacketListener.h" +#include "oscpack/ip/TimerListener.h" #if defined(__APPLE__) && !defined(_SOCKLEN_T) From 9532e998b0b2f8093854a23bfcc5c1838d54b836 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 8 Mar 2017 20:43:17 -0700 Subject: [PATCH 015/192] cleanup with using namespace in header files, start of new interaction class for touch input --- modules/touch/CMakeLists.txt | 2 + modules/touch/include/TouchInteraction.h | 108 ++++++++++++++++ modules/touch/include/TuioEar.h | 31 +++-- modules/touch/src/TouchInteraction.cpp | 151 +++++++++++++++++++++++ modules/touch/src/TuioEar.cpp | 32 ++--- modules/touch/touchmodule.cpp | 12 +- modules/touch/touchmodule.h | 12 +- 7 files changed, 300 insertions(+), 48 deletions(-) create mode 100644 modules/touch/include/TouchInteraction.h create mode 100644 modules/touch/src/TouchInteraction.cpp diff --git a/modules/touch/CMakeLists.txt b/modules/touch/CMakeLists.txt index 96a5b695bb..0951da2c6b 100644 --- a/modules/touch/CMakeLists.txt +++ b/modules/touch/CMakeLists.txt @@ -26,11 +26,13 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/TuioEar.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/TouchInteraction.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/TuioEar.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/TouchInteraction.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h new file mode 100644 index 0000000000..78bae0e5eb --- /dev/null +++ b/modules/touch/include/TouchInteraction.h @@ -0,0 +1,108 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_TOUCH___INTERACTION___H__ +#define __OPENSPACE_TOUCH___INTERACTION___H__ + +#include +#include + +#include +#include +#include + +#include + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED +#include +#include +#include +#endif + +#include + +#define ROT 0 +#define PINCH 1 +#define PAN 2 +#define PICK 3 + +using Point = std::pair; + +class TouchInteraction +{ + public: + TouchInteraction(); + ~TouchInteraction(); + + void update(const std::vector& list, std::vector& lastProcessed); + int interpret(const std::vector& list); + void performStep(double dt); + + + // Get & Setters + openspace::Camera* TouchInteraction::getCamera(); + openspace::SceneGraphNode* TouchInteraction::getFocusNode(); + double TouchInteraction::getFriction(); + double TouchInteraction::getSensitivity(); + + void setFocusNode(openspace::SceneGraphNode* focusNode); + void setCamera(openspace::Camera* cam); + void setFriction(double friction); + void setSensitivity(double sensitivity); + + + #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED + // later work + #endif + + private: + double _dt; + int _interactionMode; + + double _sensitivity; + double _friction; + + glm::dvec3 _cameraPosition; + glm::dquat _localCameraRotation; + glm::dquat _globalCameraRotation; + glm::dvec3 _centroid; + + glm::dvec3 _velocityPos; + glm::dvec3 _velocityRot; + + openspace::Camera* _camera; + openspace::SceneGraphNode* _focusNode; + //bool globebrowsing; + + #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED + // later work + #endif + +}; + + #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED + //globebrowsing::RenderableGlobe* _globe; + #endif + +#endif // __OPENSPACE_TOUCH___INTERACTION___H__ \ No newline at end of file diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index ab3a73c78f..9a13a0a19a 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -39,9 +39,8 @@ #include #include -using namespace TUIO; -class TuioEar : public TuioListener { +class TuioEar : public TUIO::TuioListener { public: TuioEar(); @@ -51,28 +50,28 @@ class TuioEar : public TuioListener { delete _oscReceiver; } - void addTuioObject(TuioObject *tobj); - void updateTuioObject(TuioObject *tobj); - void removeTuioObject(TuioObject *tobj); + void addTuioObject(TUIO::TuioObject *tobj); + void updateTuioObject(TUIO::TuioObject *tobj); + void removeTuioObject(TUIO::TuioObject *tobj); - void addTuioCursor(TuioCursor *tcur); - void updateTuioCursor(TuioCursor *tcur); - void removeTuioCursor(TuioCursor *tcur); + void addTuioCursor(TUIO::TuioCursor *tcur); + void updateTuioCursor(TUIO::TuioCursor *tcur); + void removeTuioCursor(TUIO::TuioCursor *tcur); - void addTuioBlob(TuioBlob *tblb); - void updateTuioBlob(TuioBlob *tblb); - void removeTuioBlob(TuioBlob *tblb); + void addTuioBlob(TUIO::TuioBlob *tblb); + void updateTuioBlob(TUIO::TuioBlob *tblb); + void removeTuioBlob(TUIO::TuioBlob *tblb); - void refresh(TuioTime frameTime); + void refresh(TUIO::TuioTime frameTime); - std::vector getInput(); + std::vector getInput(); void clearInput(); private: - TuioClient *_tuioClient; - OscReceiver *_oscReceiver; + TUIO::TuioClient *_tuioClient; + TUIO::OscReceiver *_oscReceiver; - std::vector _list; + std::vector _list; std::vector _removeList; std::mutex _mx; }; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp new file mode 100644 index 0000000000..0ce91a5026 --- /dev/null +++ b/modules/touch/src/TouchInteraction.cpp @@ -0,0 +1,151 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED +#include +#include +#include +#endif + + +namespace { + const std::string _loggerCat = "TouchInteraction"; +} + +using namespace TUIO; +using namespace openspace; + +TouchInteraction::TouchInteraction() + : _dt{ 0.0 }, _sensitivity{ 1.0 }, _friction{ 0.8 }, _focusNode{ nullptr }, + _camera{ OsEng.interactionHandler().camera() }, + _cameraPosition{ OsEng.interactionHandler().camera()->positionVec3() }, // initialise local/global rotations? + _velocityPos { glm::dvec3(0.0) }, _velocityRot{ glm::dvec3(0.0) }, _centroid{ glm::dvec3(0.0) } + {} + +TouchInteraction::~TouchInteraction() { } + +void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { + _cameraPosition = _camera->positionVec3(); + + double distance; + double lastDistance; + double zoomFactor; + glm::dvec3 focusDir; + + _interactionMode = interpret(list); + switch (_interactionMode) { + case ROT: + // add rotation velocity + break; + case PINCH: + // add zooming velocity + focusDir = glm::normalize(_camera->focusPositionVec3() - _cameraPosition); + + _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + + distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { + return d + sqrt(pow(c.getX() - _centroid.x, 2) + pow(c.getY() - _centroid.y, 2)); + }); + lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { + return d + sqrt(pow(p.second.getX() - _centroid.x, 2) + pow(p.second.getY() - _centroid.y, 2)); + }); + zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode + zoomFactor *= glm::distance(_cameraPosition, _camera->focusPositionVec3()); + + _velocityPos += focusDir*zoomFactor; + break; + case PAN: + // add local rotation velocity + break; + default: + LINFO("Couldn't interpret input" << "\n"); + } + +} + + +int TouchInteraction::interpret(const std::vector& list) { + if (list.size() == 1) + return ROT; + else + return PINCH; +} + +void TouchInteraction::performStep(double dt) { + if (dt != _dt) { + _cameraPosition += _velocityPos * (dt - _dt); + _velocityPos *= _friction; + if (glm::length(_velocityPos) < 100) // max of zero to have a shut off range + _velocityPos = glm::dvec3(0.0); + + _dt = dt; + + // Update the camera state + _camera->setPositionVec3(_cameraPosition); + //_camera->setRotation(_globalCameraRotation * _localCameraRotation); + } +} + + +// Getters +Camera* TouchInteraction::getCamera() { + return _camera; +} +SceneGraphNode* TouchInteraction::getFocusNode() { + return _focusNode; +} +double TouchInteraction::getFriction() { + return _friction; +} +double TouchInteraction::getSensitivity() { + return _sensitivity; +} +// Setters +void TouchInteraction::setCamera(Camera* camera) { + _camera = camera; +} +void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { + _focusNode = focusNode; +} +void TouchInteraction::setFriction(double friction) { + _friction = glm::max(friction, 0.0); +} +void TouchInteraction::setSensitivity(double sensitivity) { + _sensitivity = sensitivity; +} diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index ee7c282d07..8850bef9af 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -34,23 +34,17 @@ #include +using namespace TUIO; namespace { const std::string _loggerCat = "TuioEar"; } -void TuioEar::addTuioObject(TuioObject *tobj) { - //std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; -} +void TuioEar::addTuioObject(TuioObject *tobj) { } -void TuioEar::updateTuioObject(TuioObject *tobj) { - //std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ") " << tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() - //<< " " << tobj->getMotionSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; -} +void TuioEar::updateTuioObject(TuioObject *tobj) { } -void TuioEar::removeTuioObject(TuioObject *tobj) { - //std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << "/" << tobj->getTuioSourceID() << ")" << std::endl; -} +void TuioEar::removeTuioObject(TuioObject *tobj) { } void TuioEar::addTuioCursor(TuioCursor *tcur) { _mx.lock(); @@ -98,22 +92,13 @@ void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.unlock(); } -void TuioEar::addTuioBlob(TuioBlob *tblb) { - std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; -} +void TuioEar::addTuioBlob(TuioBlob *tblb) { } -void TuioEar::updateTuioBlob(TuioBlob *tblb) { - std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() - << " " << tblb->getMotionSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel() << " " << tblb->getRotationAccel() << std::endl; -} +void TuioEar::updateTuioBlob(TuioBlob *tblb) { } -void TuioEar::removeTuioBlob(TuioBlob *tblb) { - std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << "/" << tblb->getTuioSourceID() << ")" << std::endl; -} +void TuioEar::removeTuioBlob(TuioBlob *tblb) { } -void TuioEar::refresh(TuioTime frameTime) { - //LINFO("refresh " << frameTime.getTotalMilliseconds() << "\n"); // about every 15ms on TuioPad app -} +void TuioEar::refresh(TuioTime frameTime) { } // about every 15ms on TuioPad app std::vector TuioEar::getInput() { std::lock_guard lock(_mx); @@ -143,7 +128,6 @@ void TuioEar::clearInput() { TuioEar::TuioEar() { _oscReceiver = new UdpReceiver(3333); - //oscReceiver = new TcpReceiver("127.0.0.1",3333); _tuioClient = new TuioClient(_oscReceiver); _tuioClient->addTuioListener(this); _tuioClient->connect(); diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 5edb6ffbfb..a689159518 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -23,7 +23,6 @@ ****************************************************************************************/ #include -#include #include #include @@ -41,6 +40,8 @@ #include // std::this_thread::sleep_for #include // std::chrono::seconds +using namespace TUIO; + namespace { const std::string _loggerCat = "TouchModule"; } @@ -48,8 +49,7 @@ namespace { namespace openspace { TuioEar TouchModule::*ear; - - + //TouchInteraction TouchModule::*touch; bool TouchModule::gotNewInput() { // Get new input from listener @@ -92,6 +92,7 @@ TouchModule::TouchModule() [&]() { LDEBUGC("TouchModule", "Initializing TuioEar"); ear = new TuioEar(); + //touch = new TouchInteraction(); } ); @@ -100,6 +101,7 @@ TouchModule::TouchModule() [&]() { LDEBUGC("TouchModule", "Deinitialize TuioEar"); delete ear; + //delete touch; } ); @@ -109,6 +111,8 @@ TouchModule::TouchModule() if (gotNewInput() && OsEng.windowWrapper().isMaster()) { //std::this_thread::sleep_for(std::chrono::seconds(1)); + //touch->update(list, lastProcessed); + Camera* cam = OsEng.interactionHandler().camera(); glm::vec3 pos = cam->positionVec3(); glm::vec3 focusDir = glm::normalize(glm::vec3(cam->focusPositionVec3()) - pos); @@ -177,6 +181,8 @@ TouchModule::TouchModule() for (const TuioCursor& c : list) { lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); } + + //touch->performStep(OsEng.render.runTime()); } ); diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index f73fd4780d..d50aa66acf 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -27,10 +27,9 @@ #include #include +#include -//using Point = std::vector::iterator; - -using Point = std::pair; +using Point = std::pair; namespace openspace { @@ -40,8 +39,11 @@ public: bool gotNewInput(); - TuioEar *ear; - std::vector list; + //TouchInteraction* touch; + TuioEar* ear; + + + std::vector list; std::vector lastProcessed; // contains an id and the TuioPoint that was processed last frame }; From cc269d6affe880b32408349c006feb6af08c59e9 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 8 Mar 2017 21:09:06 -0700 Subject: [PATCH 016/192] build fix on touchinteraction header file --- modules/touch/include/TouchInteraction.h | 8 ++++---- modules/touch/src/TouchInteraction.cpp | 2 +- modules/touch/touchmodule.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 78bae0e5eb..c7055011e8 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -61,10 +61,10 @@ class TouchInteraction // Get & Setters - openspace::Camera* TouchInteraction::getCamera(); - openspace::SceneGraphNode* TouchInteraction::getFocusNode(); - double TouchInteraction::getFriction(); - double TouchInteraction::getSensitivity(); + openspace::Camera* getCamera(); + openspace::SceneGraphNode* getFocusNode(); + double getFriction(); + double getSensitivity(); void setFocusNode(openspace::SceneGraphNode* focusNode); void setCamera(openspace::Camera* cam); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 0ce91a5026..49162470d8 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -144,7 +144,7 @@ void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { _focusNode = focusNode; } void TouchInteraction::setFriction(double friction) { - _friction = glm::max(friction, 0.0); + _friction = std::max(friction, 0.0); } void TouchInteraction::setSensitivity(double sensitivity) { _sensitivity = sensitivity; diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index a689159518..eb05d3f2ab 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -182,7 +182,7 @@ TouchModule::TouchModule() lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); } - //touch->performStep(OsEng.render.runTime()); + //touch->performStep(OsEng.windowWrapper->averageDeltaTime()); } ); From fc2a9b03d2acf9c73686607c5ed2a44c1f20ea3a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 9 Mar 2017 14:43:18 -0700 Subject: [PATCH 017/192] zooming now uses velocity to move the camera, rotation works with one touch input although currently with a direct new position --- modules/touch/include/TouchInteraction.h | 8 +- modules/touch/src/TouchInteraction.cpp | 108 ++++++++++++++++------- modules/touch/touchmodule.cpp | 54 ++---------- modules/touch/touchmodule.h | 3 +- 4 files changed, 93 insertions(+), 80 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index c7055011e8..51e02c3775 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -57,7 +58,7 @@ class TouchInteraction void update(const std::vector& list, std::vector& lastProcessed); int interpret(const std::vector& list); - void performStep(double dt); + void step(double dt); // Get & Setters @@ -77,19 +78,22 @@ class TouchInteraction #endif private: - double _dt; int _interactionMode; double _sensitivity; double _friction; glm::dvec3 _cameraPosition; + glm::dvec3 _previousFocusNodePosition; glm::dquat _localCameraRotation; glm::dquat _globalCameraRotation; + + glm::dvec3 _centroid; glm::dvec3 _velocityPos; glm::dvec3 _velocityRot; + glm::dvec3 _rotationDiff; openspace::Camera* _camera; openspace::SceneGraphNode* _focusNode; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 49162470d8..6fb122b422 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -42,6 +42,7 @@ #include #endif +#include namespace { const std::string _loggerCat = "TouchInteraction"; @@ -51,48 +52,94 @@ using namespace TUIO; using namespace openspace; TouchInteraction::TouchInteraction() - : _dt{ 0.0 }, _sensitivity{ 1.0 }, _friction{ 0.8 }, _focusNode{ nullptr }, + : _sensitivity{ 1.0 }, _friction{ 0.98 }, _focusNode{ OsEng.interactionHandler().focusNode() }, _camera{ OsEng.interactionHandler().camera() }, + _globalCameraRotation{ glm::dquat(0.0, 0.0, 0.0, 0.0) }, _localCameraRotation{ glm::dquat(0.0, 0.0, 0.0, 0.0) }, _cameraPosition{ OsEng.interactionHandler().camera()->positionVec3() }, // initialise local/global rotations? - _velocityPos { glm::dvec3(0.0) }, _velocityRot{ glm::dvec3(0.0) }, _centroid{ glm::dvec3(0.0) } + _velocityPos{ glm::dvec3(0.0) }, _velocityRot{ glm::dvec3(0.0) }, _centroid{ glm::dvec3(0.0) }, + _previousFocusNodePosition{ glm::dvec3(0.0) } {} TouchInteraction::~TouchInteraction() { } -void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { +void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { + using namespace glm; + + // Create variables from current state + _focusNode = OsEng.interactionHandler().focusNode(); _cameraPosition = _camera->positionVec3(); + dvec3 centerPos = _focusNode->worldPosition(); + if (length(_previousFocusNodePosition) == 0) // ugly check to not make startup freak out + _previousFocusNodePosition = centerPos; - double distance; - double lastDistance; - double zoomFactor; - glm::dvec3 focusDir; + TuioCursor cursor = list.at(0); + // Follow the focus node + dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; + _previousFocusNodePosition = centerPos; + _cameraPosition += focusNodeDiff; + + dquat totalRotation = _camera->rotationQuaternion(); + dvec3 directionToCenter = normalize(centerPos - _cameraPosition); + dvec3 centerToCamera = _cameraPosition - centerPos; + dvec3 lookUp = _camera->lookUpVectorWorldSpace(); + dvec3 camDirection = _camera->viewDirectionWorldSpace(); + + // Create the internal representation of the local and global camera rotations + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction + _globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); + _localCameraRotation = inverse(_globalCameraRotation) * totalRotation; + _interactionMode = interpret(list); switch (_interactionMode) { - case ROT: - // add rotation velocity - break; - case PINCH: - // add zooming velocity - focusDir = glm::normalize(_camera->focusPositionVec3() - _cameraPosition); + case ROT: { // add rotation velocity + // Do global rotation + dvec2 rotationVelocity = dvec2(cursor.getXSpeed()*0.1, cursor.getYSpeed()*0.1); + dvec3 eulerAngles(rotationVelocity.y, rotationVelocity.x, 0); + dquat rotationDiffCamSpace = dquat(eulerAngles); + dquat newRotationCamspace = _globalCameraRotation * rotationDiffCamSpace; + dquat rotationDiffWorldSpace = newRotationCamspace * inverse(_globalCameraRotation); + _rotationDiff = centerToCamera * rotationDiffWorldSpace - centerToCamera; // _velocityPos += rotationDiffVec3 + + + _cameraPosition += _rotationDiff; + centerToCamera = _cameraPosition - centerPos; + directionToCenter = normalize(-centerToCamera); + + dvec3 lookUpWhenFacingCenter = _globalCameraRotation * dvec3(_camera->lookUpVectorCameraSpace()); + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + lookUpWhenFacingCenter); + _globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); + + _camera->setPositionVec3(_cameraPosition); + _camera->setRotation(_globalCameraRotation * _localCameraRotation); + break; + } + case PINCH: { // add zooming velocity _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { + double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { return d + sqrt(pow(c.getX() - _centroid.x, 2) + pow(c.getY() - _centroid.y, 2)); }); - lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { + double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { return d + sqrt(pow(p.second.getX() - _centroid.x, 2) + pow(p.second.getY() - _centroid.y, 2)); }); - zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode + double zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode zoomFactor *= glm::distance(_cameraPosition, _camera->focusPositionVec3()); - - _velocityPos += focusDir*zoomFactor; + // gets really crazy if you set a velocity when we're far away, limit zooming to not go into globe + _velocityPos += directionToCenter*zoomFactor; break; - case PAN: - // add local rotation velocity + } + case PAN: { // add local rotation velocity break; + } default: LINFO("Couldn't interpret input" << "\n"); } @@ -107,19 +154,18 @@ int TouchInteraction::interpret(const std::vector& list) { return PINCH; } -void TouchInteraction::performStep(double dt) { - if (dt != _dt) { - _cameraPosition += _velocityPos * (dt - _dt); - _velocityPos *= _friction; - if (glm::length(_velocityPos) < 100) // max of zero to have a shut off range - _velocityPos = glm::dvec3(0.0); +void TouchInteraction::step(double dt) { + _cameraPosition = _camera->positionVec3(); + _cameraPosition += _velocityPos * dt; + _velocityPos *= _friction; - _dt = dt; - // Update the camera state - _camera->setPositionVec3(_cameraPosition); - //_camera->setRotation(_globalCameraRotation * _localCameraRotation); - } + // Update the camera state + _camera->setPositionVec3(_cameraPosition); + //_camera->setRotation(_globalCameraRotation * _localCameraRotation); // need to initialize these camerarotations + + + } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index eb05d3f2ab..6ddf2d057b 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -49,7 +49,7 @@ namespace { namespace openspace { TuioEar TouchModule::*ear; - //TouchInteraction TouchModule::*touch; + TouchInteraction *touch; bool TouchModule::gotNewInput() { // Get new input from listener @@ -92,7 +92,7 @@ TouchModule::TouchModule() [&]() { LDEBUGC("TouchModule", "Initializing TuioEar"); ear = new TuioEar(); - //touch = new TouchInteraction(); + touch = new TouchInteraction(); } ); @@ -101,7 +101,7 @@ TouchModule::TouchModule() [&]() { LDEBUGC("TouchModule", "Deinitialize TuioEar"); delete ear; - //delete touch; + delete touch; } ); @@ -109,47 +109,11 @@ TouchModule::TouchModule() OpenSpaceEngine::CallbackOption::PreSync, [&]() { if (gotNewInput() && OsEng.windowWrapper().isMaster()) { + touch->update(list, lastProcessed); + + // for debugging //std::this_thread::sleep_for(std::chrono::seconds(1)); - - //touch->update(list, lastProcessed); - - Camera* cam = OsEng.interactionHandler().camera(); - glm::vec3 pos = cam->positionVec3(); - glm::vec3 focusDir = glm::normalize(glm::vec3(cam->focusPositionVec3()) - pos); - - glm::vec2 centroid; - float distance = 0.0f; - float lastDistance = 0.0f; - float zoomFactor = 0.0f; - - if (list.size() > 1) { // calculate centroid if we have multiple IDs - centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](float x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); - centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](float y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - - // ------- testing, should use more than just one point later on - distance = std::accumulate(list.begin(), list.end(), 0.0f, [¢roid](float d, const TuioCursor& c) { - return d + sqrt(pow(c.getX() - centroid.x, 2) + pow(c.getY() - centroid.y, 2)); - }); - lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [¢roid](float d, const Point& p) { - return d + sqrt(pow(p.second.getX() - centroid.x, 2) + pow(p.second.getY() - centroid.y, 2)); - }); - zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode - zoomFactor *= glm::distance(pos, glm::vec3(cam->focusPositionVec3())); - - std::cout << "Distance: " << distance << ", Last Distance: " << lastDistance << ", zoomFactor: " << zoomFactor - << "\n"; - - glm::vec3 newPos = pos + focusDir*zoomFactor; - cam->setPosition(newPos); - } - else { // do new rotation, work with spherical coordinates. Orbit it both position and rotation, check OrbitInteractionMode in interactionmode - //cam->rotate(rot); - } - // ---------------- - - - std::ostringstream os; // for debugging - + std::ostringstream os; for (const TuioCursor &j : list) { // go through each item std::list path = j.getPath(); @@ -169,7 +133,6 @@ TouchModule::TouchModule() count++; os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count; - } LINFO("List size: " << list.size() << os.str() << "\n"); os.clear(); @@ -181,8 +144,7 @@ TouchModule::TouchModule() for (const TuioCursor& c : list) { lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); } - - //touch->performStep(OsEng.windowWrapper->averageDeltaTime()); + touch->step(OsEng.windowWrapper().deltaTime()); } ); diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index d50aa66acf..e12297f413 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -39,10 +39,11 @@ public: bool gotNewInput(); - //TouchInteraction* touch; + //TouchInteraction touch; TuioEar* ear; +private: std::vector list; std::vector lastProcessed; // contains an id and the TuioPoint that was processed last frame From 7339b7c006757f0056d14a7eca9fd589ab291a1d Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 10 Mar 2017 13:45:52 -0700 Subject: [PATCH 018/192] global rotation is now also based on velocity and friction. the input only adds to the specific velocity its interaction corresponds to --- modules/touch/include/TouchInteraction.h | 47 +++++--- modules/touch/src/TouchInteraction.cpp | 139 ++++++++++++----------- 2 files changed, 103 insertions(+), 83 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 51e02c3775..27102dceb3 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -48,6 +48,21 @@ #define PAN 2 #define PICK 3 +struct VelocityStates { + double zoom; + glm::vec2 globalRot; + glm::vec2 localRot; + glm::vec2 localRoll; + glm::vec2 globalRoll; +}; +struct Friction { + double zoom; + double globalRot; + double localRot; + double localRoll; + double globalRoll; +}; + using Point = std::pair; class TouchInteraction @@ -59,6 +74,7 @@ class TouchInteraction void update(const std::vector& list, std::vector& lastProcessed); int interpret(const std::vector& list); void step(double dt); + void decelerate(); // Get & Setters @@ -78,25 +94,22 @@ class TouchInteraction #endif private: - int _interactionMode; - - double _sensitivity; - double _friction; - - glm::dvec3 _cameraPosition; - glm::dvec3 _previousFocusNodePosition; - glm::dquat _localCameraRotation; - glm::dquat _globalCameraRotation; - - - glm::dvec3 _centroid; - - glm::dvec3 _velocityPos; - glm::dvec3 _velocityRot; - glm::dvec3 _rotationDiff; - openspace::Camera* _camera; openspace::SceneGraphNode* _focusNode; + + int _interactionMode; + double _sensitivity; + double _baseFriction; + + glm::dvec3 _previousFocusNodePosition; + glm::dvec3 _centroid; + + VelocityStates _vel; + Friction _friction; + + + + //bool globebrowsing; #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 6fb122b422..61eb439928 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -52,73 +52,23 @@ using namespace TUIO; using namespace openspace; TouchInteraction::TouchInteraction() - : _sensitivity{ 1.0 }, _friction{ 0.98 }, _focusNode{ OsEng.interactionHandler().focusNode() }, - _camera{ OsEng.interactionHandler().camera() }, - _globalCameraRotation{ glm::dquat(0.0, 0.0, 0.0, 0.0) }, _localCameraRotation{ glm::dquat(0.0, 0.0, 0.0, 0.0) }, - _cameraPosition{ OsEng.interactionHandler().camera()->positionVec3() }, // initialise local/global rotations? - _velocityPos{ glm::dvec3(0.0) }, _velocityRot{ glm::dvec3(0.0) }, _centroid{ glm::dvec3(0.0) }, + : _focusNode{ OsEng.interactionHandler().focusNode() }, _camera{ OsEng.interactionHandler().camera() }, + _sensitivity{ 1.0 }, _baseFriction{ 0.02 }, + _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0) }, + _friction{ _baseFriction, 0.01, _baseFriction, _baseFriction, _baseFriction }, + _centroid{ glm::dvec3(0.0) }, _previousFocusNodePosition{ glm::dvec3(0.0) } {} TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - using namespace glm; - - // Create variables from current state - _focusNode = OsEng.interactionHandler().focusNode(); - _cameraPosition = _camera->positionVec3(); - dvec3 centerPos = _focusNode->worldPosition(); - if (length(_previousFocusNodePosition) == 0) // ugly check to not make startup freak out - _previousFocusNodePosition = centerPos; - TuioCursor cursor = list.at(0); - - // Follow the focus node - dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; - _previousFocusNodePosition = centerPos; - _cameraPosition += focusNodeDiff; - - dquat totalRotation = _camera->rotationQuaternion(); - dvec3 directionToCenter = normalize(centerPos - _cameraPosition); - dvec3 centerToCamera = _cameraPosition - centerPos; - dvec3 lookUp = _camera->lookUpVectorWorldSpace(); - dvec3 camDirection = _camera->viewDirectionWorldSpace(); - - // Create the internal representation of the local and global camera rotations - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - directionToCenter, - normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction - _globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); - _localCameraRotation = inverse(_globalCameraRotation) * totalRotation; _interactionMode = interpret(list); switch (_interactionMode) { case ROT: { // add rotation velocity - // Do global rotation - dvec2 rotationVelocity = dvec2(cursor.getXSpeed()*0.1, cursor.getYSpeed()*0.1); - dvec3 eulerAngles(rotationVelocity.y, rotationVelocity.x, 0); - dquat rotationDiffCamSpace = dquat(eulerAngles); - - dquat newRotationCamspace = _globalCameraRotation * rotationDiffCamSpace; - dquat rotationDiffWorldSpace = newRotationCamspace * inverse(_globalCameraRotation); - _rotationDiff = centerToCamera * rotationDiffWorldSpace - centerToCamera; // _velocityPos += rotationDiffVec3 - - - _cameraPosition += _rotationDiff; - centerToCamera = _cameraPosition - centerPos; - directionToCenter = normalize(-centerToCamera); - - dvec3 lookUpWhenFacingCenter = _globalCameraRotation * dvec3(_camera->lookUpVectorCameraSpace()); - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - directionToCenter, - lookUpWhenFacingCenter); - _globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); - - _camera->setPositionVec3(_cameraPosition); - _camera->setRotation(_globalCameraRotation * _localCameraRotation); + _vel.globalRot += glm::dvec2(cursor.getXSpeed()*0.1, cursor.getYSpeed()*0.1); break; } case PINCH: { // add zooming velocity @@ -132,9 +82,9 @@ void TouchInteraction::update(const std::vector& list, std::vector

focusPositionVec3()); + zoomFactor *= glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); // gets really crazy if you set a velocity when we're far away, limit zooming to not go into globe - _velocityPos += directionToCenter*zoomFactor; + _vel.zoom += zoomFactor; break; } case PAN: { // add local rotation velocity @@ -155,19 +105,76 @@ int TouchInteraction::interpret(const std::vector& list) { } void TouchInteraction::step(double dt) { - _cameraPosition = _camera->positionVec3(); - _cameraPosition += _velocityPos * dt; - _velocityPos *= _friction; + using namespace glm; + // Create variables from current state + _focusNode = OsEng.interactionHandler().focusNode(); + dvec3 camPos = _camera->positionVec3(); + dvec3 centerPos = _focusNode->worldPosition(); + if (length(_previousFocusNodePosition) == 0) // ugly check to not make startup freak out + _previousFocusNodePosition = centerPos; + + // Follow the focus node + dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; + _previousFocusNodePosition = centerPos; + camPos += focusNodeDiff; + + dvec3 directionToCenter = normalize(centerPos - camPos); + dvec3 centerToCamera = camPos - centerPos; + dvec3 lookUp = _camera->lookUpVectorWorldSpace(); + dvec3 camDirection = _camera->viewDirectionWorldSpace(); + + // Make a representation of the rotation quaternion with local and global rotations + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction + dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); + dquat localCameraRotation = inverse(globalCameraRotation) * _camera->rotationQuaternion(); + + + { // Orbit (global rotation) + dvec2 smoothVelocity = _vel.globalRot*dt; + dvec3 eulerAngles(smoothVelocity.y, smoothVelocity.x, 0); + dquat rotationDiffCamSpace = dquat(eulerAngles); + + dquat newRotationCamspace = globalCameraRotation * rotationDiffCamSpace; + dquat rotationDiffWorldSpace = newRotationCamspace * inverse(globalCameraRotation); + dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; + + camPos += rotationDiffVec3; + dvec3 centerToCamera = camPos - centerPos; + directionToCenter = normalize(-centerToCamera); + + dvec3 lookUpWhenFacingCenter = + globalCameraRotation * dvec3(_camera->lookUpVectorCameraSpace()); + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + lookUpWhenFacingCenter); + globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); + } + { // Zooming + camPos += directionToCenter*_vel.zoom*dt; + } + + decelerate(); // Update the camera state - _camera->setPositionVec3(_cameraPosition); - //_camera->setRotation(_globalCameraRotation * _localCameraRotation); // need to initialize these camerarotations - + _camera->setPositionVec3(camPos); + _camera->setRotation(globalCameraRotation * localCameraRotation); } +void TouchInteraction::decelerate() { + _vel.zoom *= (1 - _friction.zoom); + _vel.globalRot *= (1 - _friction.globalRot); + _vel.localRot *= (1 - _friction.localRot); + _vel.globalRoll *= (1 - _friction.globalRoll); + _vel.localRoll *= (1 - _friction.localRoll); +} + // Getters Camera* TouchInteraction::getCamera() { @@ -177,7 +184,7 @@ SceneGraphNode* TouchInteraction::getFocusNode() { return _focusNode; } double TouchInteraction::getFriction() { - return _friction; + return _baseFriction; } double TouchInteraction::getSensitivity() { return _sensitivity; @@ -190,7 +197,7 @@ void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { _focusNode = focusNode; } void TouchInteraction::setFriction(double friction) { - _friction = std::max(friction, 0.0); + _baseFriction = std::max(friction, 0.0); } void TouchInteraction::setSensitivity(double sensitivity) { _sensitivity = sensitivity; From b1e507ce2befb538d9c5d8667299a2abc9d1774f Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 10 Mar 2017 14:23:06 -0700 Subject: [PATCH 019/192] small cleanup and bugfix on gotNewInput() --- modules/touch/include/TouchInteraction.h | 9 +----- modules/touch/src/TouchInteraction.cpp | 41 ++++++++++++------------ modules/touch/touchmodule.cpp | 14 ++++---- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 27102dceb3..5d851fe8ad 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -96,26 +96,19 @@ class TouchInteraction private: openspace::Camera* _camera; openspace::SceneGraphNode* _focusNode; + glm::dvec3 _previousFocusNodePosition; int _interactionMode; double _sensitivity; double _baseFriction; - - glm::dvec3 _previousFocusNodePosition; - glm::dvec3 _centroid; VelocityStates _vel; Friction _friction; - - - //bool globebrowsing; - #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED // later work #endif - }; #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 61eb439928..7af311d55c 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -53,10 +53,9 @@ using namespace openspace; TouchInteraction::TouchInteraction() : _focusNode{ OsEng.interactionHandler().focusNode() }, _camera{ OsEng.interactionHandler().camera() }, - _sensitivity{ 1.0 }, _baseFriction{ 0.02 }, + _sensitivity{ 0.5 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0) }, - _friction{ _baseFriction, 0.01, _baseFriction, _baseFriction, _baseFriction }, - _centroid{ glm::dvec3(0.0) }, + _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, _previousFocusNodePosition{ glm::dvec3(0.0) } {} @@ -64,26 +63,28 @@ TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { TuioCursor cursor = list.at(0); - + glm::dvec3 centroid; + _interactionMode = interpret(list); + if (_interactionMode != ROT) { + centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + } + switch (_interactionMode) { case ROT: { // add rotation velocity - _vel.globalRot += glm::dvec2(cursor.getXSpeed()*0.1, cursor.getYSpeed()*0.1); + _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity; break; } case PINCH: { // add zooming velocity - _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); - _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { - return d + sqrt(pow(c.getX() - _centroid.x, 2) + pow(c.getY() - _centroid.y, 2)); + return d + sqrt(pow(c.getX() - centroid.x, 2) + pow(c.getY() - centroid.y, 2)); }); double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { - return d + sqrt(pow(p.second.getX() - _centroid.x, 2) + pow(p.second.getY() - _centroid.y, 2)); + return d + sqrt(pow(p.second.getX() - centroid.x, 2) + pow(p.second.getY() - centroid.y, 2)); }); - double zoomFactor = distance - lastDistance; // should be dependant on screen size, distance from focusNode - zoomFactor *= glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); - // gets really crazy if you set a velocity when we're far away, limit zooming to not go into globe + + double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); _vel.zoom += zoomFactor; break; } @@ -129,8 +130,8 @@ void TouchInteraction::step(double dt) { dvec3(0, 0, 0), directionToCenter, normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction - dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); - dquat localCameraRotation = inverse(globalCameraRotation) * _camera->rotationQuaternion(); + dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); { // Orbit (global rotation) @@ -138,8 +139,8 @@ void TouchInteraction::step(double dt) { dvec3 eulerAngles(smoothVelocity.y, smoothVelocity.x, 0); dquat rotationDiffCamSpace = dquat(eulerAngles); - dquat newRotationCamspace = globalCameraRotation * rotationDiffCamSpace; - dquat rotationDiffWorldSpace = newRotationCamspace * inverse(globalCameraRotation); + dquat newRotationCamspace = globalCamRot * rotationDiffCamSpace; + dquat rotationDiffWorldSpace = newRotationCamspace * inverse(globalCamRot); dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; camPos += rotationDiffVec3; @@ -147,12 +148,12 @@ void TouchInteraction::step(double dt) { directionToCenter = normalize(-centerToCamera); dvec3 lookUpWhenFacingCenter = - globalCameraRotation * dvec3(_camera->lookUpVectorCameraSpace()); + globalCamRot * dvec3(_camera->lookUpVectorCameraSpace()); dmat4 lookAtMat = lookAt( dvec3(0, 0, 0), directionToCenter, lookUpWhenFacingCenter); - globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); + globalCamRot = normalize(quat_cast(inverse(lookAtMat))); } { // Zooming camPos += directionToCenter*_vel.zoom*dt; @@ -162,7 +163,7 @@ void TouchInteraction::step(double dt) { // Update the camera state _camera->setPositionVec3(camPos); - _camera->setRotation(globalCameraRotation * localCameraRotation); + _camera->setRotation(globalCamRot * localCamRot); } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 6ddf2d057b..084ca4c5c3 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -72,12 +72,14 @@ bool TouchModule::gotNewInput() { lastProcessed.end()); // Return true if we got new input + if (list.size() == lastProcessed.size() && list.size() > 0) { - for_each(lastProcessed.begin(), lastProcessed.end(), [this](Point& p) { - if (p.second.getTuioTime() == find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; })->getPath().back().getTuioTime()) - return false; + bool newInput = true; + for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { + if (p.second.getTuioTime().getTotalMilliseconds() == find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; })->getPath().back().getTuioTime().getTotalMilliseconds()) + newInput = false; }); - return true; + return newInput; } else return false; @@ -128,11 +130,11 @@ TouchModule::TouchModule() path.end(), [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); - int count = 0; + int count = -1; for (; lastPoint != path.end(); ++lastPoint) // here we can access all elements that are to be processed count++; - os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", (" << j.getX() << "," << j.getY() << "), To Process: " << count; + os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", To Process: " << count; } LINFO("List size: " << list.size() << os.str() << "\n"); os.clear(); From 6b0b2070ef2f32ec68f59927f92dcc47cbaca798 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 10 Mar 2017 15:48:44 -0700 Subject: [PATCH 020/192] panning kinda works --- modules/touch/include/TouchInteraction.h | 7 ++-- modules/touch/src/TouchInteraction.cpp | 45 ++++++++++++++++++++---- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 5d851fe8ad..80294a17b2 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -46,7 +46,8 @@ #define ROT 0 #define PINCH 1 #define PAN 2 -#define PICK 3 +#define ROLL 3 +#define PICK 4 struct VelocityStates { double zoom; @@ -72,7 +73,7 @@ class TouchInteraction ~TouchInteraction(); void update(const std::vector& list, std::vector& lastProcessed); - int interpret(const std::vector& list); + int interpret(const std::vector& list, const std::vector& lastProcessed); void step(double dt); void decelerate(); @@ -98,6 +99,8 @@ class TouchInteraction openspace::SceneGraphNode* _focusNode; glm::dvec3 _previousFocusNodePosition; + + double _dt; int _interactionMode; double _sensitivity; double _baseFriction; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 7af311d55c..80e0ea4af2 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -56,7 +56,7 @@ TouchInteraction::TouchInteraction() _sensitivity{ 0.5 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0) }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, - _previousFocusNodePosition{ glm::dvec3(0.0) } + _previousFocusNodePosition{ glm::dvec3(0.0) }, _dt{ 0.0 } {} TouchInteraction::~TouchInteraction() { } @@ -65,7 +65,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

positionVec3(), _camera->focusPositionVec3()); - _vel.zoom += zoomFactor; + _vel.zoom += zoomFactor * (_sensitivity*3.0); break; } case PAN: { // add local rotation velocity + _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity * 0.5; + break; + } + case ROLL: { // add global roll rotation velocity + break; + } + case PICK: { // pick something in the scene as focus node break; } default: @@ -98,11 +105,29 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list) { +int TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { + double dist = 0; + double lastDist = 0; + TuioCursor cursor = list.at(0); + for (const TuioCursor& c : list) { + dist += glm::length(glm::dvec2(c.getX(), c.getY()) - glm::dvec2(cursor.getX(), cursor.getY())); + cursor = c; + } + TuioPoint point = lastProcessed.at(0).second; + for (const Point& p : lastProcessed) { + dist += glm::length(glm::dvec2(p.second.getX(), p.second.getY()) - glm::dvec2(point.getX(), point.getY())); + point = p.second; + } + if (list.size() == 1) return ROT; - else - return PINCH; + else { + if (std::abs(dist - lastDist)/list.size() < 0.05) + return PAN; + else + return PINCH; + } + } void TouchInteraction::step(double dt) { @@ -133,7 +158,13 @@ void TouchInteraction::step(double dt) { dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); - + { // Panning (local rotation) + dvec2 smoothVelocity = _vel.localRot*dt; + dvec3 eulerAngles(-smoothVelocity.y, -smoothVelocity.x, 0); + dquat rotationDiff = dquat(eulerAngles); + + localCamRot = localCamRot * rotationDiff; + } { // Orbit (global rotation) dvec2 smoothVelocity = _vel.globalRot*dt; dvec3 eulerAngles(smoothVelocity.y, smoothVelocity.x, 0); From 88db722006be777bb787a535282e0f12b0188d2b Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 10 Mar 2017 16:18:15 -0700 Subject: [PATCH 021/192] ugly minHeightFromSurface check on focus node (only earth) --- modules/touch/include/TouchInteraction.h | 2 +- modules/touch/src/TouchInteraction.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 80294a17b2..02c2a04c0c 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -100,7 +100,7 @@ class TouchInteraction glm::dvec3 _previousFocusNodePosition; - double _dt; + double _minHeightFromSurface; int _interactionMode; double _sensitivity; double _baseFriction; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 80e0ea4af2..2fb90a94fc 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -56,7 +56,7 @@ TouchInteraction::TouchInteraction() _sensitivity{ 0.5 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0) }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, - _previousFocusNodePosition{ glm::dvec3(0.0) }, _dt{ 0.0 } + _previousFocusNodePosition{ glm::dvec3(0.0) }, _minHeightFromSurface{ 6.6 * 1000000.0 } {} TouchInteraction::~TouchInteraction() { } @@ -85,7 +85,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

positionVec3(), _camera->focusPositionVec3()); - _vel.zoom += zoomFactor * (_sensitivity*3.0); + _vel.zoom += zoomFactor / _sensitivity; break; } case PAN: { // add local rotation velocity @@ -187,7 +187,11 @@ void TouchInteraction::step(double dt) { globalCamRot = normalize(quat_cast(inverse(lookAtMat))); } { // Zooming - camPos += directionToCenter*_vel.zoom*dt; + dvec3 centerToCamera = camPos - centerPos; + if (length(_vel.zoom*dt) < length(centerToCamera) && length(centerToCamera) > _minHeightFromSurface) // should get boundingsphere from focusnode + camPos += directionToCenter*_vel.zoom*dt; + else + _vel.zoom = 0.0; } decelerate(); From bb050d5056a2ad30fc53d50656cf8f787c0e03b9 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Mon, 13 Mar 2017 23:09:17 -0600 Subject: [PATCH 022/192] small modifications to sensitivity and panning --- modules/touch/src/TouchInteraction.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 2fb90a94fc..20520dfca7 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -53,7 +53,7 @@ using namespace openspace; TouchInteraction::TouchInteraction() : _focusNode{ OsEng.interactionHandler().focusNode() }, _camera{ OsEng.interactionHandler().camera() }, - _sensitivity{ 0.5 }, _baseFriction{ 0.02 }, + _sensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0) }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, _previousFocusNodePosition{ glm::dvec3(0.0) }, _minHeightFromSurface{ 6.6 * 1000000.0 } @@ -83,12 +83,16 @@ void TouchInteraction::update(const std::vector& list, std::vector

positionVec3(), _camera->focusPositionVec3()); - _vel.zoom += zoomFactor / _sensitivity; + _vel.zoom += zoomFactor * 2.0; break; } case PAN: { // add local rotation velocity + glm::dvec3 lastCentroid; + lastCentroid.x = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [](double x, const Point& p) { return x + p.second.getX(); }) / lastProcessed.size(); + lastCentroid.y = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [](double y, const Point& p) { return y + p.second.getY(); }) / lastProcessed.size(); + _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity * 0.5; break; } @@ -119,10 +123,11 @@ int TouchInteraction::interpret(const std::vector& list, const std:: point = p.second; } + std::cout << std::abs(dist - lastDist) / list.size() << "\n"; if (list.size() == 1) return ROT; else { - if (std::abs(dist - lastDist)/list.size() < 0.05) + if (std::abs(dist - lastDist)/list.size() < 0.3 && list.size() == 2) return PAN; else return PINCH; @@ -188,7 +193,7 @@ void TouchInteraction::step(double dt) { } { // Zooming dvec3 centerToCamera = camPos - centerPos; - if (length(_vel.zoom*dt) < length(centerToCamera) && length(centerToCamera) > _minHeightFromSurface) // should get boundingsphere from focusnode + if (length(_vel.zoom*dt) < length(centerToCamera) && length(centerToCamera) > _minHeightFromSurface && length(camPos+directionToCenter*_vel.zoom*dt) > length(centerToCamera)) // should get boundingsphere from focusnode camPos += directionToCenter*_vel.zoom*dt; else _vel.zoom = 0.0; From 1fa5220e3c59ae1268553d35f9da319c61ed9971 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 14 Mar 2017 12:44:43 -0600 Subject: [PATCH 023/192] minor changes during meeting --- data/scene/lodglobes/mars/mars.mod | 2 +- modules/touch/include/TouchInteraction.h | 21 +++++++++++++-------- modules/touch/touchmodule.cpp | 3 ++- modules/touch/touchmodule.h | 4 +++- src/engine/openspaceengine.cpp | 5 ++++- 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/data/scene/lodglobes/mars/mars.mod b/data/scene/lodglobes/mars/mars.mod index 040fc570e8..ca0e4a0206 100644 --- a/data/scene/lodglobes/mars/mars.mod +++ b/data/scene/lodglobes/mars/mars.mod @@ -116,7 +116,7 @@ return { HeightLayers = { { Name = "Mola Elevation", - FilePath = "map_service_configs/Utah/Mola_Elevation.xml", + FilePath = "map_service_configs/Mola_Elevation.xml", Enabled = true, MinimumPixelSize = 90, DoPreProcessing = true, diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 02c2a04c0c..84ca3fc091 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -49,6 +50,8 @@ #define ROLL 3 #define PICK 4 +namespace openspace { + struct VelocityStates { double zoom; glm::vec2 globalRot; @@ -66,7 +69,7 @@ struct Friction { using Point = std::pair; -class TouchInteraction +class TouchInteraction : public properties::PropertyOwner { public: TouchInteraction(); @@ -79,13 +82,13 @@ class TouchInteraction // Get & Setters - openspace::Camera* getCamera(); - openspace::SceneGraphNode* getFocusNode(); + Camera* getCamera(); + SceneGraphNode* getFocusNode(); double getFriction(); double getSensitivity(); - void setFocusNode(openspace::SceneGraphNode* focusNode); - void setCamera(openspace::Camera* cam); + void setFocusNode(SceneGraphNode* focusNode); + void setCamera(Camera* cam); void setFriction(double friction); void setSensitivity(double sensitivity); @@ -95,8 +98,8 @@ class TouchInteraction #endif private: - openspace::Camera* _camera; - openspace::SceneGraphNode* _focusNode; + Camera* _camera; + SceneGraphNode* _focusNode; glm::dvec3 _previousFocusNodePosition; @@ -117,5 +120,7 @@ class TouchInteraction #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED //globebrowsing::RenderableGlobe* _globe; #endif +} // namespace + +#endif // __OPENSPACE_TOUCH___INTERACTION___H__ -#endif // __OPENSPACE_TOUCH___INTERACTION___H__ \ No newline at end of file diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 084ca4c5c3..d4fc7f0356 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -95,9 +95,10 @@ TouchModule::TouchModule() LDEBUGC("TouchModule", "Initializing TuioEar"); ear = new TuioEar(); touch = new TouchInteraction(); + addPropertySubOwner(touch); } ); - + OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::Deinitialize, [&]() { diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index e12297f413..e68deffc42 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -29,10 +29,12 @@ #include #include -using Point = std::pair; + namespace openspace { +using Point = std::pair; + class TouchModule : public OpenSpaceModule { public: TouchModule(); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 71318c29b3..594b7d41c4 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -851,7 +851,7 @@ void OpenSpaceEngine::preSynchronization() { _renderEngine->updateSceneGraph(); _interactionHandler->updateCamera(dt); - _renderEngine->camera()->invalidateCache(); + _parallelConnection->preSynchronization(); @@ -860,6 +860,9 @@ void OpenSpaceEngine::preSynchronization() { for (const auto& func : _moduleCallbacks.preSync) { func(); } + if (master) + _renderEngine->camera()->invalidateCache(); + LTRACE("OpenSpaceEngine::preSynchronization(end)"); } From 868ac5c6a68fdb2223c9fafad2439de146cc2eb7 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 14 Mar 2017 16:27:01 -0600 Subject: [PATCH 024/192] first pass on roll (only uses three finger and x-pos atm), Friction and sensitivities are now part of struct ScaleFactor, sensitivities of zoom and globalRot scales with distance to focus node --- modules/touch/include/TouchInteraction.h | 37 ++++----- modules/touch/src/TouchInteraction.cpp | 96 +++++++++++++++++------- 2 files changed, 82 insertions(+), 51 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 84ca3fc091..e6652c7438 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -54,17 +54,17 @@ namespace openspace { struct VelocityStates { double zoom; - glm::vec2 globalRot; - glm::vec2 localRot; - glm::vec2 localRoll; - glm::vec2 globalRoll; + glm::dvec2 globalRot; + glm::dvec2 localRot; + double globalRoll; + double localRoll; }; -struct Friction { +struct ScaleFactor { double zoom; double globalRot; double localRot; - double localRoll; double globalRoll; + double localRoll; }; using Point = std::pair; @@ -78,6 +78,7 @@ class TouchInteraction : public properties::PropertyOwner void update(const std::vector& list, std::vector& lastProcessed); int interpret(const std::vector& list, const std::vector& lastProcessed); void step(double dt); + void configSensitivities(double dist); void decelerate(); @@ -92,35 +93,25 @@ class TouchInteraction : public properties::PropertyOwner void setFriction(double friction); void setSensitivity(double sensitivity); - - #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - // later work - #endif - private: Camera* _camera; SceneGraphNode* _focusNode; + globebrowsing::RenderableGlobe* _globe; glm::dvec3 _previousFocusNodePosition; - + glm::dquat _previousFocusNodeRotation; double _minHeightFromSurface; int _interactionMode; - double _sensitivity; + double _baseSensitivity; double _baseFriction; VelocityStates _vel; - Friction _friction; - - //bool globebrowsing; - #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - // later work - #endif + ScaleFactor _friction; + ScaleFactor _sensitivity; + }; - #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - //globebrowsing::RenderableGlobe* _globe; - #endif -} // namespace +} // openspace namespace #endif // __OPENSPACE_TOUCH___INTERACTION___H__ diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 20520dfca7..89cdffdb72 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -53,9 +53,10 @@ using namespace openspace; TouchInteraction::TouchInteraction() : _focusNode{ OsEng.interactionHandler().focusNode() }, _camera{ OsEng.interactionHandler().camera() }, - _sensitivity{ 0.1 }, _baseFriction{ 0.02 }, - _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0), glm::dvec2(0.0) }, + _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, + _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, + _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, _previousFocusNodePosition{ glm::dvec3(0.0) }, _minHeightFromSurface{ 6.6 * 1000000.0 } {} @@ -73,7 +74,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

positionVec3(), _camera->focusPositionVec3()); - _vel.zoom += zoomFactor * 2.0; + _vel.zoom += zoomFactor * _sensitivity.zoom; break; } case PAN: { // add local rotation velocity - glm::dvec3 lastCentroid; - lastCentroid.x = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [](double x, const Point& p) { return x + p.second.getX(); }) / lastProcessed.size(); - lastCentroid.y = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [](double y, const Point& p) { return y + p.second.getY(); }) / lastProcessed.size(); - - _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity * 0.5; + _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; break; } case ROLL: { // add global roll rotation velocity + double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [](double s, const TuioCursor& c) { + return s + c.getXSpeed(); + }); + _vel.localRoll += rollFactor * _sensitivity.localRoll; break; } case PICK: { // pick something in the scene as focus node break; } default: - LINFO("Couldn't interpret input" << "\n"); + LINFO("Couldn't interpret touch input" << "\n"); } } @@ -123,12 +124,13 @@ int TouchInteraction::interpret(const std::vector& list, const std:: point = p.second; } - std::cout << std::abs(dist - lastDist) / list.size() << "\n"; if (list.size() == 1) return ROT; else { - if (std::abs(dist - lastDist)/list.size() < 0.3 && list.size() == 2) + if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) return PAN; + else if (list.size() == 3) + return ROLL; else return PINCH; } @@ -163,28 +165,30 @@ void TouchInteraction::step(double dt) { dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); - { // Panning (local rotation) - dvec2 smoothVelocity = _vel.localRot*dt; - dvec3 eulerAngles(-smoothVelocity.y, -smoothVelocity.x, 0); - dquat rotationDiff = dquat(eulerAngles); + double boundingSphere = _focusNode->boundingSphere().lengthf(); + double minHeightAboveBoundingSphere = 1; + dvec3 centerToBoundingSphere; + + { // Roll + dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); + localCamRot = localCamRot * camRollRot; + } + { // Panning (local rotation) + dvec3 eulerAngles(-_vel.localRot.y*dt, -_vel.localRot.x*dt, 0); + dquat rotationDiff = dquat(eulerAngles); localCamRot = localCamRot * rotationDiff; } { // Orbit (global rotation) - dvec2 smoothVelocity = _vel.globalRot*dt; - dvec3 eulerAngles(smoothVelocity.y, smoothVelocity.x, 0); + dvec3 eulerAngles(_vel.globalRot.y*dt, _vel.globalRot.x*dt, 0); dquat rotationDiffCamSpace = dquat(eulerAngles); - dquat newRotationCamspace = globalCamRot * rotationDiffCamSpace; - dquat rotationDiffWorldSpace = newRotationCamspace * inverse(globalCamRot); + dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; - camPos += rotationDiffVec3; - dvec3 centerToCamera = camPos - centerPos; - directionToCenter = normalize(-centerToCamera); - dvec3 lookUpWhenFacingCenter = - globalCamRot * dvec3(_camera->lookUpVectorCameraSpace()); + directionToCenter = normalize(-(camPos - centerPos)); + dvec3 lookUpWhenFacingCenter = globalCamRot * dvec3(_camera->lookUpVectorCameraSpace()); dmat4 lookAtMat = lookAt( dvec3(0, 0, 0), directionToCenter, @@ -192,13 +196,27 @@ void TouchInteraction::step(double dt) { globalCamRot = normalize(quat_cast(inverse(lookAtMat))); } { // Zooming + centerToBoundingSphere = -directionToCenter * boundingSphere; dvec3 centerToCamera = camPos - centerPos; - if (length(_vel.zoom*dt) < length(centerToCamera) && length(centerToCamera) > _minHeightFromSurface && length(camPos+directionToCenter*_vel.zoom*dt) > length(centerToCamera)) // should get boundingsphere from focusnode + if (length(_vel.zoom*dt) < length(centerToCamera) && length(centerToCamera) > length(centerToBoundingSphere)) // should get boundingsphere from focusnode + camPos += directionToCenter*_vel.zoom*dt; + else if (length(centerToCamera) < length(centerToBoundingSphere) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToCamera)) camPos += directionToCenter*_vel.zoom*dt; else _vel.zoom = 0.0; } + { // Roll around sphere normal + dquat camRollRot = angleAxis(_vel.globalRoll*dt, -directionToCenter); + globalCamRot = camRollRot * globalCamRot; + } + { // Push up to surface + dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere); + double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera); + camPos += -directionToCenter * max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); + } + double dist = length(camPos - (centerPos + centerToBoundingSphere)); + configSensitivities(dist); decelerate(); // Update the camera state @@ -206,6 +224,28 @@ void TouchInteraction::step(double dt) { _camera->setRotation(globalCamRot * localCamRot); +} + + +void TouchInteraction::configSensitivities(double dist) { + // Configurates sensitivities to appropriate values when the camera is close to the focus node. + double close = 4.6 * 1000000; + if (dist < close) { + _sensitivity.zoom = 2.0 * dist/close; + _sensitivity.globalRot = 0.1 * dist/close; + //_sensitivity.localRot = 0.1; + //_sensitivity.globalRoll = 0.1; + //_sensitivity.localRoll = 0.1; + } + else { + _sensitivity.zoom = 2.0; + _sensitivity.globalRot = 0.1; + _sensitivity.localRot = 0.1; + _sensitivity.globalRoll = 0.1; + _sensitivity.localRoll = 0.3; + } + + } void TouchInteraction::decelerate() { @@ -228,7 +268,7 @@ double TouchInteraction::getFriction() { return _baseFriction; } double TouchInteraction::getSensitivity() { - return _sensitivity; + return _baseSensitivity; } // Setters void TouchInteraction::setCamera(Camera* camera) { @@ -241,5 +281,5 @@ void TouchInteraction::setFriction(double friction) { _baseFriction = std::max(friction, 0.0); } void TouchInteraction::setSensitivity(double sensitivity) { - _sensitivity = sensitivity; + _baseSensitivity = sensitivity; } From 6f03e5fe80b830e18c48327b3f83783e657d0cc6 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 15 Mar 2017 10:22:00 -0600 Subject: [PATCH 025/192] Bugfix to losing focus node on fast zooming --- modules/touch/src/TouchInteraction.cpp | 12 +++++------- modules/touch/touchmodule.cpp | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 89cdffdb72..99e67ddf50 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -129,8 +129,8 @@ int TouchInteraction::interpret(const std::vector& list, const std:: else { if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) return PAN; - else if (list.size() == 3) - return ROLL; + //else if (list.size() == 3) + //return ROLL; else return PINCH; } @@ -198,9 +198,7 @@ void TouchInteraction::step(double dt) { { // Zooming centerToBoundingSphere = -directionToCenter * boundingSphere; dvec3 centerToCamera = camPos - centerPos; - if (length(_vel.zoom*dt) < length(centerToCamera) && length(centerToCamera) > length(centerToBoundingSphere)) // should get boundingsphere from focusnode - camPos += directionToCenter*_vel.zoom*dt; - else if (length(centerToCamera) < length(centerToBoundingSphere) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToCamera)) + if (length(_vel.zoom*dt) < length(centerToCamera - centerToBoundingSphere) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) // should get boundingsphere from focusnode camPos += directionToCenter*_vel.zoom*dt; else _vel.zoom = 0.0; @@ -231,8 +229,8 @@ void TouchInteraction::configSensitivities(double dist) { // Configurates sensitivities to appropriate values when the camera is close to the focus node. double close = 4.6 * 1000000; if (dist < close) { - _sensitivity.zoom = 2.0 * dist/close; - _sensitivity.globalRot = 0.1 * dist/close; + _sensitivity.zoom = 2.0 * std::max(dist, 100.0)/close; + _sensitivity.globalRot = 0.1 * std::max(dist, 100.0) /close; //_sensitivity.localRot = 0.1; //_sensitivity.globalRoll = 0.1; //_sensitivity.localRoll = 0.1; diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index d4fc7f0356..977dcd01f7 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -137,7 +137,7 @@ TouchModule::TouchModule() os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", To Process: " << count; } - LINFO("List size: " << list.size() << os.str() << "\n"); + //LINFO("List size: " << list.size() << os.str() << "\n"); os.clear(); } From 0db8581630ae9297b065c89d92095d8319d677c8 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 15 Mar 2017 17:25:50 +0100 Subject: [PATCH 026/192] Fix crash in initialization of touch interaction --- modules/touch/src/TouchInteraction.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 89cdffdb72..87bf67c116 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -52,13 +52,15 @@ using namespace TUIO; using namespace openspace; TouchInteraction::TouchInteraction() - : _focusNode{ OsEng.interactionHandler().focusNode() }, _camera{ OsEng.interactionHandler().camera() }, - _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, - _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, - _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, - _previousFocusNodePosition{ glm::dvec3(0.0) }, _minHeightFromSurface{ 6.6 * 1000000.0 } - {} + : PropertyOwner("TouchInteraction") + , _focusNode{ OsEng.interactionHandler().focusNode() } + , _camera{ OsEng.interactionHandler().camera() } + , _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 } + , _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 } + , _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction } + , _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 } + , _previousFocusNodePosition{ glm::dvec3(0.0) }, _minHeightFromSurface{ 6.6 * 1000000.0 } + {} TouchInteraction::~TouchInteraction() { } From dd7bb15c30d668e5dd20603836cd3d6385f4061c Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Wed, 15 Mar 2017 17:29:11 +0100 Subject: [PATCH 027/192] Clean up touch interaction init list --- modules/touch/src/TouchInteraction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index ce664aee53..2dbc7bcfc1 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -59,8 +59,8 @@ TouchInteraction::TouchInteraction() , _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 } , _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction } , _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 } - , _previousFocusNodePosition{ glm::dvec3(0.0) }, _minHeightFromSurface{ 6.6 * 1000000.0 } - {} + , _previousFocusNodePosition{ glm::dvec3(0.0) } + , _minHeightFromSurface{ 6.6 * 1000000.0 } {} TouchInteraction::~TouchInteraction() { } From 7989c7bbd98e9b5fab88586aab4ee933d7dc3d7c Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 16 Mar 2017 13:39:42 -0600 Subject: [PATCH 028/192] allow globebrowsing.scene to render mercury --- data/scene/lodglobes/mercury/mercury.mod | 101 +++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 data/scene/lodglobes/mercury/mercury.mod diff --git a/data/scene/lodglobes/mercury/mercury.mod b/data/scene/lodglobes/mercury/mercury.mod new file mode 100644 index 0000000000..8e211d3c5e --- /dev/null +++ b/data/scene/lodglobes/mercury/mercury.mod @@ -0,0 +1,101 @@ +return { + -- Barycenter module + { + Name = "MercuryBarycenter", + Parent = "SolarSystemBarycenter", + Transform = { + Translation = { + Type = "SpiceTranslation", + Body = "MERCURY", + Observer = "SUN", + Kernels = "${OPENSPACE_DATA}/spice/de430_1850-2150.bsp" + }, + }, + }, + -- RenderableGlobe module + { + Name = "Mercury", + Parent = "MercuryBarycenter", + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "IAU_MERCURY", + DestinationFrame = "GALACTIC", + }, + Scale = { + Type = "StaticScale", + Scale = 1, + }, + }, + Renderable = { + Type = "RenderableGlobe", + Radii = {2439700, 2439700.0, 2439700.0}, + Frame = "IAU_MERCURY", + Body = "MERCURY", + + CameraMinHeight = 300, + InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values + SegmentsPerPatch = 64, + Layers = { + ColorLayers = { + { + Name = "Simple Texture", + FilePath = "textures/mercury.jpg", + Enabled = true, + MinimumPixelSize = 256, + }, + { + Name = "Messenger_Mosaic", + FilePath = "map_service_configs/Utah/MessengerMosaic.wms" + } + --[[ + { + Name = "On Mercury Color", + FilePath = "map_service_configs/OnMercuryColor.xml", + Enabled = true, + }, + { + Name = "On Mercury Image", + FilePath = "map_service_configs/OnMercuryImage.xml", + }, + ]] + }, + GrayScaleLayers = { + { + Name = "Messenger_MDIS", + FilePath = "map_service_configs/Utah/MessengerMDIS.wms" + } + }, + GrayScaleColorOverlays = { }, + NightLayers = { }, + WaterMasks = { }, + ColorOverlays = { }, + HeightLayers = { + --[[ + { + Name = "On Mercury Height", + FilePath = "map_service_configs/OnMercuryElevationGaskell.xml", + Enabled = true, + }, + ]] + }, + }, + }, + }, + -- Trail module + { + Name = "MercuryTrail", + Parent = "SolarSystemBarycenter", + Renderable = { + Type = "RenderableTrailOrbit", + Translation = { + Type = "SpiceTranslation", + Body = "MERCURY", + Observer = "SUN", + }, + Color = {0.6, 0.5, 0.5 }, + Period = 87.968, + Resolution = 100 + } + } +} From 2e3cd2e5997f5909bd687ef1f0477bacd91499ea Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 16 Mar 2017 13:40:29 -0600 Subject: [PATCH 029/192] Touch interaction works decently on globebrowsing and newhorizon scenes. Pause globebrowsing to freeze focus nodes orbit --- .../interaction/interactionhandler.h | 1 + modules/touch/include/TouchInteraction.h | 4 +- modules/touch/src/TouchInteraction.cpp | 178 ++++++++++-------- openspace.cfg | 2 +- src/interaction/interactionhandler.cpp | 4 + src/interaction/interactionmode.cpp | 15 +- 6 files changed, 121 insertions(+), 83 deletions(-) diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/interactionhandler.h index 34c398186c..7583cc0112 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/interactionhandler.h @@ -97,6 +97,7 @@ public: ghoul::Dictionary getCameraStateDictionary(); SceneGraphNode* const focusNode() const; Camera* const camera() const; + std::shared_ptr interactionmode(); const InputState& inputState() const; /** diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index e6652c7438..ef586ea320 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -95,7 +95,9 @@ class TouchInteraction : public properties::PropertyOwner private: Camera* _camera; - SceneGraphNode* _focusNode; + SceneGraphNode* _focusNode = nullptr; + properties::StringProperty _origin; + globebrowsing::RenderableGlobe* _globe; glm::dvec3 _previousFocusNodePosition; glm::dquat _previousFocusNodeRotation; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 99e67ddf50..88b07dfcc5 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -25,6 +25,7 @@ #include +#include #include #include #include @@ -52,13 +53,23 @@ using namespace TUIO; using namespace openspace; TouchInteraction::TouchInteraction() - : _focusNode{ OsEng.interactionHandler().focusNode() }, _camera{ OsEng.interactionHandler().camera() }, + : properties::PropertyOwner("TouchInteraction"), + _origin("origin", "Origin", ""), _camera{ OsEng.interactionHandler().camera() }, _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, - _previousFocusNodePosition{ glm::dvec3(0.0) }, _minHeightFromSurface{ 6.6 * 1000000.0 } - {} + _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, _minHeightFromSurface{ 6.6 * 1000000.0 } +{ + _origin.onChange([this]() { + SceneGraphNode* node = sceneGraphNode(_origin.value()); + if (!node) { + LWARNING("Could not find a node in scenegraph called '" << _origin.value() << "'"); + return; + } + setFocusNode(node); + }); + +} TouchInteraction::~TouchInteraction() { } @@ -140,88 +151,96 @@ int TouchInteraction::interpret(const std::vector& list, const std:: void TouchInteraction::step(double dt) { using namespace glm; - // Create variables from current state - _focusNode = OsEng.interactionHandler().focusNode(); - dvec3 camPos = _camera->positionVec3(); - dvec3 centerPos = _focusNode->worldPosition(); - if (length(_previousFocusNodePosition) == 0) // ugly check to not make startup freak out + if (_focusNode) { + // Create variables from current state + dvec3 camPos = _camera->positionVec3(); + + // Follow the focus node + dquat totRot = _camera->rotationQuaternion(); + dvec3 centerPos = _focusNode->worldPosition(); + dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; _previousFocusNodePosition = centerPos; + camPos += focusNodeDiff; - // Follow the focus node - dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; - _previousFocusNodePosition = centerPos; - camPos += focusNodeDiff; + dvec3 directionToCenter = normalize(centerPos - camPos); + dvec3 centerToCamera = camPos - centerPos; + dvec3 lookUp = _camera->lookUpVectorWorldSpace(); + dvec3 camDirection = _camera->viewDirectionWorldSpace(); - dvec3 directionToCenter = normalize(centerPos - camPos); - dvec3 centerToCamera = camPos - centerPos; - dvec3 lookUp = _camera->lookUpVectorWorldSpace(); - dvec3 camDirection = _camera->viewDirectionWorldSpace(); - - // Make a representation of the rotation quaternion with local and global rotations - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - directionToCenter, - normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction - dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); - - - double boundingSphere = _focusNode->boundingSphere().lengthf(); - double minHeightAboveBoundingSphere = 1; - dvec3 centerToBoundingSphere; - - { // Roll - dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); - localCamRot = localCamRot * camRollRot; - } - { // Panning (local rotation) - dvec3 eulerAngles(-_vel.localRot.y*dt, -_vel.localRot.x*dt, 0); - dquat rotationDiff = dquat(eulerAngles); - localCamRot = localCamRot * rotationDiff; - } - { // Orbit (global rotation) - dvec3 eulerAngles(_vel.globalRot.y*dt, _vel.globalRot.x*dt, 0); - dquat rotationDiffCamSpace = dquat(eulerAngles); - - dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); - dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; - camPos += rotationDiffVec3; - - directionToCenter = normalize(-(camPos - centerPos)); - dvec3 lookUpWhenFacingCenter = globalCamRot * dvec3(_camera->lookUpVectorCameraSpace()); + // Make a representation of the rotation quaternion with local and global rotations dmat4 lookAtMat = lookAt( dvec3(0, 0, 0), directionToCenter, - lookUpWhenFacingCenter); - globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - } - { // Zooming - centerToBoundingSphere = -directionToCenter * boundingSphere; - dvec3 centerToCamera = camPos - centerPos; - if (length(_vel.zoom*dt) < length(centerToCamera - centerToBoundingSphere) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) // should get boundingsphere from focusnode - camPos += directionToCenter*_vel.zoom*dt; - else - _vel.zoom = 0.0; - } - { // Roll around sphere normal - dquat camRollRot = angleAxis(_vel.globalRoll*dt, -directionToCenter); - globalCamRot = camRollRot * globalCamRot; - } - { // Push up to surface - dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere); - double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera); - camPos += -directionToCenter * max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); - } + normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction + dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + dquat localCamRot = inverse(globalCamRot) * totRot; - double dist = length(camPos - (centerPos + centerToBoundingSphere)); - configSensitivities(dist); - decelerate(); - // Update the camera state - _camera->setPositionVec3(camPos); - _camera->setRotation(globalCamRot * localCamRot); + double boundingSphere = _focusNode->boundingSphere().lengthf(); + double minHeightAboveBoundingSphere = 1; + dvec3 centerToBoundingSphere; - + { // Roll + dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); + localCamRot = localCamRot * camRollRot; + } + { // Panning (local rotation) + dvec3 eulerAngles(-_vel.localRot.y*dt, -_vel.localRot.x*dt, 0); + dquat rotationDiff = dquat(eulerAngles); + localCamRot = localCamRot * rotationDiff; + } + { // Orbit (global rotation) + dvec3 eulerAngles(_vel.globalRot.y*dt, _vel.globalRot.x*dt, 0); + dquat rotationDiffCamSpace = dquat(eulerAngles); + + dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); + dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; + camPos += rotationDiffVec3; + + dvec3 centerToCamera = camPos - centerPos; + directionToCenter = normalize(-centerToCamera); + dvec3 lookUpWhenFacingCenter = globalCamRot * dvec3(_camera->lookUpVectorCameraSpace()); + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + lookUpWhenFacingCenter); + globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + } + { // Zooming + centerToBoundingSphere = -directionToCenter * boundingSphere; + dvec3 centerToCamera = camPos - centerPos; + if (length(_vel.zoom*dt) < length(centerToCamera - centerToBoundingSphere) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) // should get boundingsphere from focusnode + camPos += directionToCenter*_vel.zoom*dt; + else + _vel.zoom = 0.0; + } + { // Roll around sphere normal + dquat camRollRot = angleAxis(_vel.globalRoll*dt, -directionToCenter); + globalCamRot = camRollRot * globalCamRot; + } + { // Push up to surface + dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere); + double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera); + camPos += -directionToCenter * max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); + } + + std::shared_ptr gbim = + std::dynamic_pointer_cast (OsEng.interactionHandler().interactionmode()); + if (gbim) { + double dist = length(camPos - (centerPos + centerToBoundingSphere)); + configSensitivities(dist); + } + decelerate(); + + // Update the camera state + _camera->setPositionVec3(camPos); + _camera->setRotation(globalCamRot * localCamRot); + } + else { + setFocusNode(OsEng.interactionHandler().focusNode()); + std::cout << "focus node set\n"; + } + } @@ -274,6 +293,11 @@ void TouchInteraction::setCamera(Camera* camera) { } void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { _focusNode = focusNode; + + if (_focusNode != nullptr) { + _previousFocusNodePosition = _focusNode->worldPosition(); + _previousFocusNodeRotation = glm::quat_cast(_focusNode->worldRotationMatrix()); + } } void TouchInteraction::setFriction(double friction) { _baseFriction = std::max(friction, 0.0); diff --git a/openspace.cfg b/openspace.cfg index 050d9758c7..87382f4356 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -23,7 +23,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/globebrowsing.scene", + Scene = "${SCENE}/newhorizons.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index 2b0dcaeff9..a9bdbf06df 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -268,6 +268,10 @@ Camera* const InteractionHandler::camera() const { return _camera; } +std::shared_ptr InteractionHandler::interactionmode() { + return _currentInteractionMode; +} + const InputState& InteractionHandler::inputState() const { return *_inputState; } diff --git a/src/interaction/interactionmode.cpp b/src/interaction/interactionmode.cpp index 539416890e..cf5787cb8b 100644 --- a/src/interaction/interactionmode.cpp +++ b/src/interaction/interactionmode.cpp @@ -481,8 +481,8 @@ void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera, do } // Update the camera state - camera.setPositionVec3(camPos); - camera.setRotation(globalCameraRotation * localCameraRotation); + //camera.setPositionVec3(camPos); + //camera.setRotation(globalCameraRotation * localCameraRotation); } } @@ -681,8 +681,15 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& came } // Update the camera state - camera.setPositionVec3(camPos); - camera.setRotation(globalCameraRotation * localCameraRotation); + //camera.setPositionVec3(camPos); + //camera.setRotation(globalCameraRotation * localCameraRotation); + + std::cout << "gRot: " << "(" << _mouseStates->synchedGlobalRotationMouseVelocity().x << "," << _mouseStates->synchedGlobalRotationMouseVelocity().y << ")" + << ", lRot: " << "(" << _mouseStates->synchedLocalRotationMouseVelocity().x << "," << _mouseStates->synchedLocalRotationMouseVelocity().y << ")" + << ", Zoom: " << "(" << _mouseStates->synchedTruckMovementMouseVelocity().x << "," << _mouseStates->synchedTruckMovementMouseVelocity().y << ")" + << ", gRoll: " << "(" << _mouseStates->synchedGlobalRollMouseVelocity().x << "," << _mouseStates->synchedGlobalRollMouseVelocity().y << ")" + << ", lRoll: " << "(" << _mouseStates->synchedLocalRollMouseVelocity().x << "," << _mouseStates->synchedLocalRollMouseVelocity().y << ")" + << "\n"; } #endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED } From 6e5686241239b46fd089dfb227f4610e86a9e95c Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 16 Mar 2017 15:28:46 -0600 Subject: [PATCH 030/192] Fix on camera issues with it not following rotation/position of focus node. configSensitivites() only done during globebrowsing now --- modules/touch/src/TouchInteraction.cpp | 6 ++---- src/interaction/interactionmode.cpp | 18 ++++++------------ 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 88b07dfcc5..af77ee827a 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -160,7 +160,7 @@ void TouchInteraction::step(double dt) { dvec3 centerPos = _focusNode->worldPosition(); dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; _previousFocusNodePosition = centerPos; - camPos += focusNodeDiff; + //camPos += focusNodeDiff; dvec3 directionToCenter = normalize(centerPos - camPos); dvec3 centerToCamera = camPos - centerPos; @@ -236,10 +236,8 @@ void TouchInteraction::step(double dt) { _camera->setPositionVec3(camPos); _camera->setRotation(globalCamRot * localCamRot); } - else { + else setFocusNode(OsEng.interactionHandler().focusNode()); - std::cout << "focus node set\n"; - } } diff --git a/src/interaction/interactionmode.cpp b/src/interaction/interactionmode.cpp index cf5787cb8b..1b9b24e909 100644 --- a/src/interaction/interactionmode.cpp +++ b/src/interaction/interactionmode.cpp @@ -42,6 +42,7 @@ #include #endif +#include namespace { const std::string _loggerCat = "InteractionMode"; @@ -395,7 +396,7 @@ void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera, do // Follow focus nodes movement dvec3 centerPos = _focusNode->worldPosition(); dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; - _previousFocusNodePosition = centerPos; + _previousFocusNodePosition = centerPos; camPos += focusNodeDiff; dquat totalRotation = camera.rotationQuaternion(); @@ -481,8 +482,8 @@ void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera, do } // Update the camera state - //camera.setPositionVec3(camPos); - //camera.setRotation(globalCameraRotation * localCameraRotation); + camera.setPositionVec3(camPos); + camera.setRotation(globalCameraRotation * localCameraRotation); } } @@ -681,15 +682,8 @@ void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& came } // Update the camera state - //camera.setPositionVec3(camPos); - //camera.setRotation(globalCameraRotation * localCameraRotation); - - std::cout << "gRot: " << "(" << _mouseStates->synchedGlobalRotationMouseVelocity().x << "," << _mouseStates->synchedGlobalRotationMouseVelocity().y << ")" - << ", lRot: " << "(" << _mouseStates->synchedLocalRotationMouseVelocity().x << "," << _mouseStates->synchedLocalRotationMouseVelocity().y << ")" - << ", Zoom: " << "(" << _mouseStates->synchedTruckMovementMouseVelocity().x << "," << _mouseStates->synchedTruckMovementMouseVelocity().y << ")" - << ", gRoll: " << "(" << _mouseStates->synchedGlobalRollMouseVelocity().x << "," << _mouseStates->synchedGlobalRollMouseVelocity().y << ")" - << ", lRoll: " << "(" << _mouseStates->synchedLocalRollMouseVelocity().x << "," << _mouseStates->synchedLocalRollMouseVelocity().y << ")" - << "\n"; + camera.setPositionVec3(camPos); + camera.setRotation(globalCameraRotation * localCameraRotation); } #endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED } From 6a696bfc5c1eceb03aa8b81fb1a2769370a45de4 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 16 Mar 2017 15:31:24 -0600 Subject: [PATCH 031/192] Cleanup on constructor of TouchInteraction --- modules/touch/src/TouchInteraction.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index af77ee827a..e64967291e 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -54,11 +54,13 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), - _origin("origin", "Origin", ""), _camera{ OsEng.interactionHandler().camera() }, + _origin("origin", "Origin", ""), + _camera{ OsEng.interactionHandler().camera() }, _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, _minHeightFromSurface{ 6.6 * 1000000.0 } + _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, + _minHeightFromSurface{ 0.0 } { _origin.onChange([this]() { SceneGraphNode* node = sceneGraphNode(_origin.value()); From 5fc52a39362e7027dabf2a85ef1fb923086a9be7 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 16 Mar 2017 17:02:16 -0600 Subject: [PATCH 032/192] trying to use c.getAngles(centroid) for roll feature, not done yet --- modules/touch/include/TouchInteraction.h | 1 + modules/touch/src/TouchInteraction.cpp | 40 ++++++++++++++++++------ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index ef586ea320..92feb74b12 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -106,6 +106,7 @@ class TouchInteraction : public properties::PropertyOwner int _interactionMode; double _baseSensitivity; double _baseFriction; + glm::dvec3 _centroid; VelocityStates _vel; ScaleFactor _friction; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index e64967291e..ea95a21120 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -59,6 +59,7 @@ TouchInteraction::TouchInteraction() _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, + _centroid{ glm::dvec3(0.0) }, _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, _minHeightFromSurface{ 0.0 } { @@ -77,14 +78,13 @@ TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { TuioCursor cursor = list.at(0); - glm::dvec3 centroid; _interactionMode = interpret(list, lastProcessed); if (_interactionMode != ROT) { - centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); - centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); } - + switch (_interactionMode) { case ROT: { // add rotation velocity _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; @@ -92,10 +92,10 @@ void TouchInteraction::update(const std::vector& list, std::vector

positionVec3(), _camera->focusPositionVec3()); @@ -107,13 +107,35 @@ void TouchInteraction::update(const std::vector& list, std::vector

second; + double diff = c.getX() - point.getX() + c.getY() - point.getY(); + if (std::abs(diff) < std::abs(minDiff)) { + minDiff = diff; + id = c.getSessionID(); + } + } + auto cTemp = find_if(list.begin(), list.end(), [&id](const TuioCursor& c) { return c.getSessionID() == id; }); + glm::dvec2 thumb = glm::dvec2(cTemp->getX(), cTemp->getY()); + double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { + auto found = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); }); + double res = diff; + if (found != lastProcessed.end()) + res += c.getAngleDegrees(thumb.x, thumb.y) - found->second.getAngleDegrees(thumb.x, thumb.y); + std::cout << res << "\n"; + return res; }); - _vel.localRoll += rollFactor * _sensitivity.localRoll; + std::cout << "Angle: " << rollFactor << "\n"; + //_vel.localRoll += rollFactor * _sensitivity.localRoll; break; } case PICK: { // pick something in the scene as focus node + //if(!cursor.isMoving()) break; } default: @@ -142,7 +164,7 @@ int TouchInteraction::interpret(const std::vector& list, const std:: else { if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) return PAN; - //else if (list.size() == 3) + //else if (list.size() == 5) //return ROLL; else return PINCH; From 6a6b01096dcf46483541d7026a01b9caeb1cd4d8 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 17 Mar 2017 11:29:49 -0600 Subject: [PATCH 033/192] cleanup of unneeded variables and working version of angle interpretation on roll --- modules/touch/include/TouchInteraction.h | 3 -- modules/touch/src/TouchInteraction.cpp | 50 ++++++++++-------------- openspace.cfg | 2 +- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 92feb74b12..fabf060ac8 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -97,10 +97,7 @@ class TouchInteraction : public properties::PropertyOwner Camera* _camera; SceneGraphNode* _focusNode = nullptr; properties::StringProperty _origin; - globebrowsing::RenderableGlobe* _globe; - glm::dvec3 _previousFocusNodePosition; - glm::dquat _previousFocusNodeRotation; double _minHeightFromSurface; int _interactionMode; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index ea95a21120..c03fe9850a 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -58,9 +58,9 @@ TouchInteraction::TouchInteraction() _camera{ OsEng.interactionHandler().camera() }, _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, - _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, + _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction/4.0 }, _centroid{ glm::dvec3(0.0) }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.3 }, + _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.5 }, _minHeightFromSurface{ 0.0 } { _origin.onChange([this]() { @@ -123,15 +123,19 @@ void TouchInteraction::update(const std::vector& list, std::vector

getX(), cTemp->getY()); double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { - auto found = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); }); + TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = diff; - if (found != lastProcessed.end()) - res += c.getAngleDegrees(thumb.x, thumb.y) - found->second.getAngleDegrees(thumb.x, thumb.y); - std::cout << res << "\n"; + if (c.getSessionID() != id) { + if (point.getAngle(thumb.x, thumb.y) > c.getAngle(thumb.x, thumb.y) + 1.5*M_PI) + res += c.getAngle(thumb.x, thumb.y) + (2*M_PI-point.getAngle(thumb.x, thumb.y)); + else if (c.getAngle(thumb.x, thumb.y) > point.getAngle(thumb.x, thumb.y) + 1.5*M_PI) + res += (2*M_PI - c.getAngle(thumb.x, thumb.y)) + point.getAngle(thumb.x, thumb.y); + else + res += c.getAngle(thumb.x, thumb.y) - point.getAngle(thumb.x, thumb.y); + } return res; }); - std::cout << "Angle: " << rollFactor << "\n"; - //_vel.localRoll += rollFactor * _sensitivity.localRoll; + _vel.localRoll += -rollFactor * _sensitivity.localRoll; break; } case PICK: { // pick something in the scene as focus node @@ -164,8 +168,8 @@ int TouchInteraction::interpret(const std::vector& list, const std:: else { if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) return PAN; - //else if (list.size() == 5) - //return ROLL; + else if (list.size() == 5) + return ROLL; else return PINCH; } @@ -178,13 +182,7 @@ void TouchInteraction::step(double dt) { if (_focusNode) { // Create variables from current state dvec3 camPos = _camera->positionVec3(); - - // Follow the focus node - dquat totRot = _camera->rotationQuaternion(); dvec3 centerPos = _focusNode->worldPosition(); - dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; - _previousFocusNodePosition = centerPos; - //camPos += focusNodeDiff; dvec3 directionToCenter = normalize(centerPos - camPos); dvec3 centerToCamera = camPos - centerPos; @@ -197,7 +195,7 @@ void TouchInteraction::step(double dt) { directionToCenter, normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - dquat localCamRot = inverse(globalCamRot) * totRot; + dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion();; double boundingSphere = _focusNode->boundingSphere().lengthf(); @@ -248,12 +246,7 @@ void TouchInteraction::step(double dt) { camPos += -directionToCenter * max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); } - std::shared_ptr gbim = - std::dynamic_pointer_cast (OsEng.interactionHandler().interactionmode()); - if (gbim) { - double dist = length(camPos - (centerPos + centerToBoundingSphere)); - configSensitivities(dist); - } + configSensitivities(length(camPos - (centerPos + centerToBoundingSphere))); decelerate(); // Update the camera state @@ -268,8 +261,10 @@ void TouchInteraction::step(double dt) { void TouchInteraction::configSensitivities(double dist) { // Configurates sensitivities to appropriate values when the camera is close to the focus node. + std::shared_ptr gbim = + std::dynamic_pointer_cast (OsEng.interactionHandler().interactionmode()); double close = 4.6 * 1000000; - if (dist < close) { + if (gbim && dist < close) { _sensitivity.zoom = 2.0 * std::max(dist, 100.0)/close; _sensitivity.globalRot = 0.1 * std::max(dist, 100.0) /close; //_sensitivity.localRot = 0.1; @@ -281,7 +276,7 @@ void TouchInteraction::configSensitivities(double dist) { _sensitivity.globalRot = 0.1; _sensitivity.localRot = 0.1; _sensitivity.globalRoll = 0.1; - _sensitivity.localRoll = 0.3; + _sensitivity.localRoll = 0.5; } @@ -315,11 +310,6 @@ void TouchInteraction::setCamera(Camera* camera) { } void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { _focusNode = focusNode; - - if (_focusNode != nullptr) { - _previousFocusNodePosition = _focusNode->worldPosition(); - _previousFocusNodeRotation = glm::quat_cast(_focusNode->worldRotationMatrix()); - } } void TouchInteraction::setFriction(double friction) { _baseFriction = std::max(friction, 0.0); diff --git a/openspace.cfg b/openspace.cfg index 87382f4356..050d9758c7 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -23,7 +23,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/newhorizons.scene", + Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", From 8c9027c6e583cd9512e591a9df3fb9236f6c8fa8 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 17 Mar 2017 12:11:08 -0600 Subject: [PATCH 034/192] allow for multiple interaction modes (mostly roll and zoom) --- modules/touch/include/TouchInteraction.h | 11 +++- modules/touch/src/TouchInteraction.cpp | 71 +++++++++++++----------- 2 files changed, 48 insertions(+), 34 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index fabf060ac8..ac3c238b94 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -66,6 +66,13 @@ struct ScaleFactor { double globalRoll; double localRoll; }; +struct InteractionType { + bool rot; + bool pinch; + bool pan; + bool roll; + bool pick; +}; using Point = std::pair; @@ -76,7 +83,7 @@ class TouchInteraction : public properties::PropertyOwner ~TouchInteraction(); void update(const std::vector& list, std::vector& lastProcessed); - int interpret(const std::vector& list, const std::vector& lastProcessed); + void interpret(const std::vector& list, const std::vector& lastProcessed); void step(double dt); void configSensitivities(double dist); void decelerate(); @@ -100,7 +107,7 @@ class TouchInteraction : public properties::PropertyOwner globebrowsing::RenderableGlobe* _globe; double _minHeightFromSurface; - int _interactionMode; + InteractionType _interactionMode; double _baseSensitivity; double _baseFriction; glm::dvec3 _centroid; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index c03fe9850a..8bff8b473f 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -60,7 +60,7 @@ TouchInteraction::TouchInteraction() _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction/4.0 }, _centroid{ glm::dvec3(0.0) }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.5 }, + _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.2 }, _minHeightFromSurface{ 0.0 } { _origin.onChange([this]() { @@ -79,18 +79,16 @@ TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { TuioCursor cursor = list.at(0); - _interactionMode = interpret(list, lastProcessed); - if (_interactionMode != ROT) { + interpret(list, lastProcessed); + if (!_interactionMode.rot) { _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); } - switch (_interactionMode) { - case ROT: { // add rotation velocity + if (_interactionMode.rot) { // add rotation velocity _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; - break; } - case PINCH: { // add zooming velocity + if (_interactionMode.pinch) { // add zooming velocity double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { return d + c.getDistance(_centroid.x, _centroid.y); }); @@ -100,13 +98,11 @@ void TouchInteraction::update(const std::vector& list, std::vector

positionVec3(), _camera->focusPositionVec3()); _vel.zoom += zoomFactor * _sensitivity.zoom; - break; } - case PAN: { // add local rotation velocity + if (_interactionMode.pan) { // add local rotation velocity _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; - break; } - case ROLL: { // add global roll rotation velocity + if (_interactionMode.roll) { // add global roll rotation velocity /*double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [](double s, const TuioCursor& c) { return s + c.getXSpeed(); });*/ @@ -121,7 +117,8 @@ void TouchInteraction::update(const std::vector& list, std::vector

getX(), cTemp->getY()); + glm::dvec2 thumb = _centroid; //glm::dvec2(cTemp->getX(), cTemp->getY()); + id = -1; double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = diff; @@ -135,21 +132,20 @@ void TouchInteraction::update(const std::vector& list, std::vector

0.2) + _vel.localRoll += -rollFactor * _sensitivity.localRoll; } - case PICK: { // pick something in the scene as focus node + if (_interactionMode.pick) { // pick something in the scene as focus node //if(!cursor.isMoving()) - break; - } - default: - LINFO("Couldn't interpret touch input" << "\n"); } + //default: + //LINFO("Couldn't interpret touch input" << "\n"); + //} } -int TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { +void TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { double dist = 0; double lastDist = 0; TuioCursor cursor = list.at(0); @@ -162,18 +158,29 @@ int TouchInteraction::interpret(const std::vector& list, const std:: dist += glm::length(glm::dvec2(p.second.getX(), p.second.getY()) - glm::dvec2(point.getX(), point.getY())); point = p.second; } - - if (list.size() == 1) - return ROT; - else { - if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) - return PAN; - else if (list.size() == 5) - return ROLL; - else - return PINCH; + if (list.size() == 1) { + _interactionMode.rot = true; + _interactionMode.pinch = false; + _interactionMode.pan = false; + _interactionMode.roll = false; + _interactionMode.pick = false; } - + else { + if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) { + _interactionMode.rot = false; + _interactionMode.pinch = false; + _interactionMode.pan = true; + _interactionMode.roll = false; + _interactionMode.pick = false; + } + else { + _interactionMode.rot = false; + _interactionMode.pinch = true; + _interactionMode.pan = false; + _interactionMode.roll = true; + _interactionMode.pick = false; + } + } } void TouchInteraction::step(double dt) { @@ -276,7 +283,7 @@ void TouchInteraction::configSensitivities(double dist) { _sensitivity.globalRot = 0.1; _sensitivity.localRot = 0.1; _sensitivity.globalRoll = 0.1; - _sensitivity.localRoll = 0.5; + _sensitivity.localRoll = 0.2; } From bc46190711a7f9fa9846da15ec3a15f7dee4d599 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 17 Mar 2017 14:43:09 -0600 Subject: [PATCH 035/192] invert panning interaction after feedback --- modules/touch/include/TouchInteraction.h | 1 + modules/touch/src/TouchInteraction.cpp | 103 ++++++++++++++++------- modules/touch/touchmodule.cpp | 22 ++--- openspace.cfg | 5 +- 4 files changed, 89 insertions(+), 42 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index ac3c238b94..34e0b41927 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -87,6 +87,7 @@ class TouchInteraction : public properties::PropertyOwner void step(double dt); void configSensitivities(double dist); void decelerate(); + void clear(); // Get & Setters diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 8bff8b473f..68a4fd1e88 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -103,40 +103,40 @@ void TouchInteraction::update(const std::vector& list, std::vector

second; - double diff = c.getX() - point.getX() + c.getY() - point.getY(); - if (std::abs(diff) < std::abs(minDiff)) { - minDiff = diff; - id = c.getSessionID(); - } - } - auto cTemp = find_if(list.begin(), list.end(), [&id](const TuioCursor& c) { return c.getSessionID() == id; }); - glm::dvec2 thumb = _centroid; //glm::dvec2(cTemp->getX(), cTemp->getY()); - id = -1; double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = diff; - if (c.getSessionID() != id) { - if (point.getAngle(thumb.x, thumb.y) > c.getAngle(thumb.x, thumb.y) + 1.5*M_PI) - res += c.getAngle(thumb.x, thumb.y) + (2*M_PI-point.getAngle(thumb.x, thumb.y)); - else if (c.getAngle(thumb.x, thumb.y) > point.getAngle(thumb.x, thumb.y) + 1.5*M_PI) - res += (2*M_PI - c.getAngle(thumb.x, thumb.y)) + point.getAngle(thumb.x, thumb.y); - else - res += c.getAngle(thumb.x, thumb.y) - point.getAngle(thumb.x, thumb.y); - } + double lastAngle = point.getAngle(_centroid.x, _centroid.y); + double currentAngle = c.getAngle(_centroid.x, _centroid.y); + if (lastAngle > currentAngle + 1.5*M_PI) + res += currentAngle + (2*M_PI - lastAngle); + else if (currentAngle > lastAngle + 1.5*M_PI) + res += (2*M_PI - currentAngle) + lastAngle; + else + res += currentAngle - lastAngle; return res; }); - if (std::abs(rollFactor) > 0.2) + double maxX = 0.0; + double minX = 1.0; + double maxY = 0.0; + double minY = 1.0; + for (const TuioCursor& c : list) { + if (c.getX() > maxX) + maxX = c.getX(); + if (c.getX() < minX) + minX = c.getX(); + if (c.getY() > maxY) + maxY = c.getY(); + if (c.getY() < minY) + minY = c.getY(); + } + double xRange = (maxX - minX) / list.size(); + double yRange = (maxY - minY) / list.size(); + //if (std::abs(rollFactor)/list.size() > 0.02) _vel.localRoll += -rollFactor * _sensitivity.localRoll; } if (_interactionMode.pick) { // pick something in the scene as focus node - //if(!cursor.isMoving()) + } //default: //LINFO("Couldn't interpret touch input" << "\n"); @@ -159,6 +159,8 @@ void TouchInteraction::interpret(const std::vector& list, const std: point = p.second; } if (list.size() == 1) { + //if(!cursor.isMoving()) // pick + _interactionMode.rot = true; _interactionMode.pinch = false; _interactionMode.pan = false; @@ -177,8 +179,41 @@ void TouchInteraction::interpret(const std::vector& list, const std: _interactionMode.rot = false; _interactionMode.pinch = true; _interactionMode.pan = false; - _interactionMode.roll = true; + //_interactionMode.roll = true; _interactionMode.pick = false; + + double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { + TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; + double res = diff; + double lastAngle = point.getAngle(_centroid.x, _centroid.y); + double currentAngle = c.getAngle(_centroid.x, _centroid.y); + if (lastAngle > currentAngle + 1.5*M_PI) + res += currentAngle + (2 * M_PI - lastAngle); + else if (currentAngle > lastAngle + 1.5*M_PI) + res += (2 * M_PI - currentAngle) + lastAngle; + else + res += currentAngle - lastAngle; + return res; + }); + double maxX = 0.0; + double minX = 1.0; + double maxY = 0.0; + double minY = 1.0; + for (const TuioCursor& c : list) { + if (c.getX() > maxX) + maxX = c.getX(); + if (c.getX() < minX) + minX = c.getX(); + if (c.getY() > maxY) + maxY = c.getY(); + if (c.getY() < minY) + minY = c.getY(); + } + double xRange = (maxX - minX) / list.size(); + double yRange = (maxY - minY) / list.size(); + if (std::abs(rollFactor) / list.size() > 0.05) + _interactionMode.roll = true; + } } } @@ -186,6 +221,7 @@ void TouchInteraction::interpret(const std::vector& list, const std: void TouchInteraction::step(double dt) { using namespace glm; + setFocusNode(OsEng.interactionHandler().focusNode()); if (_focusNode) { // Create variables from current state dvec3 camPos = _camera->positionVec3(); @@ -214,7 +250,7 @@ void TouchInteraction::step(double dt) { localCamRot = localCamRot * camRollRot; } { // Panning (local rotation) - dvec3 eulerAngles(-_vel.localRot.y*dt, -_vel.localRot.x*dt, 0); + dvec3 eulerAngles(_vel.localRot.y*dt, _vel.localRot.x*dt, 0); dquat rotationDiff = dquat(eulerAngles); localCamRot = localCamRot * rotationDiff; } @@ -260,9 +296,6 @@ void TouchInteraction::step(double dt) { _camera->setPositionVec3(camPos); _camera->setRotation(globalCamRot * localCamRot); } - else - setFocusNode(OsEng.interactionHandler().focusNode()); - } @@ -297,6 +330,14 @@ void TouchInteraction::decelerate() { _vel.localRoll *= (1 - _friction.localRoll); } +void TouchInteraction::clear() { + _interactionMode.rot = false; + _interactionMode.pinch = false; + _interactionMode.pan = false; + _interactionMode.roll = false; + _interactionMode.pick = false; +} + // Getters Camera* TouchInteraction::getCamera() { diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 977dcd01f7..92db5c9679 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -116,21 +116,21 @@ TouchModule::TouchModule() // for debugging //std::this_thread::sleep_for(std::chrono::seconds(1)); - std::ostringstream os; + std::ostringstream os; for (const TuioCursor &j : list) { // go through each item std::list path = j.getPath(); - + TuioTime lastTime = find_if( - lastProcessed.begin(), - lastProcessed.end(), - [&j](const Point& p) { return p.first == j.getSessionID(); } + lastProcessed.begin(), + lastProcessed.end(), + [&j](const Point& p) { return p.first == j.getSessionID(); } )->second.getTuioTime(); - + std::list::iterator lastPoint = find_if( - path.begin(), - path.end(), - [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); - + path.begin(), + path.end(), + [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); + int count = -1; for (; lastPoint != path.end(); ++lastPoint) // here we can access all elements that are to be processed count++; @@ -141,6 +141,8 @@ TouchModule::TouchModule() os.clear(); } + else + touch->clear(); // update lastProcessed lastProcessed.clear(); diff --git a/openspace.cfg b/openspace.cfg index 050d9758c7..46ed8b5a0c 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,8 +7,11 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, + SGCTConfig = sgct.config.single{}, + -- Fullscreen mode + --SGCTConfig = sgct.config.single{fullScreen=true}, + -- A regular 1920x1080 window -- SGCTConfig = sgct.config.single{1920, 1080}, From 0ea349a70cdb5fe3473d374db38551cd15d9adbb Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 28 Mar 2017 14:15:23 -0600 Subject: [PATCH 036/192] convert cursor coordinates to ray direction in world space and calculate the distance from planets to the ray to get picking --- modules/touch/include/TouchInteraction.h | 6 +- modules/touch/src/TouchInteraction.cpp | 99 ++++++++++++------------ openspace.cfg | 4 +- 3 files changed, 57 insertions(+), 52 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 34e0b41927..c41a132a72 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -107,8 +107,12 @@ class TouchInteraction : public properties::PropertyOwner properties::StringProperty _origin; globebrowsing::RenderableGlobe* _globe; + + bool _directTouchMode; + double _projectionScaleFactor; + double _currentRadius; double _minHeightFromSurface; - InteractionType _interactionMode; + InteractionType _action; double _baseSensitivity; double _baseFriction; glm::dvec3 _centroid; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 68a4fd1e88..70fa8396f4 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -61,7 +61,8 @@ TouchInteraction::TouchInteraction() _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction/4.0 }, _centroid{ glm::dvec3(0.0) }, _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.2 }, - _minHeightFromSurface{ 0.0 } + _projectionScaleFactor{ 1.000004 }, + _directTouchMode{ false } { _origin.onChange([this]() { SceneGraphNode* node = sceneGraphNode(_origin.value()); @@ -79,16 +80,30 @@ TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { TuioCursor cursor = list.at(0); + if (_currentRadius > 0.3) // good value to make any planet sufficiently large for direct-touch + _directTouchMode = true; + else + _directTouchMode = false; + + + double xCo = 2 * (cursor.getX() - 0.5); + double yCo = -2 * (cursor.getY() - 0.5); // normalized -1 to 1 coordinates on screen + glm::dvec3 cursorInWorldSpace = _camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -1.0); + glm::dvec3 camToCenter = _focusNode->worldPosition() - _camera->positionVec3(); + double dist = std::max(length(glm::cross(cursorInWorldSpace, camToCenter)) / length(cursorInWorldSpace) - _focusNode->boundingSphere().lengthd(), 0.0); + + std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(cursorInWorldSpace) << "\n"; + interpret(list, lastProcessed); - if (!_interactionMode.rot) { + if (!_action.rot) { _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); } - if (_interactionMode.rot) { // add rotation velocity + if (_action.rot) { // add rotation velocity _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; } - if (_interactionMode.pinch) { // add zooming velocity + if (_action.pinch) { // add zooming velocity double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { return d + c.getDistance(_centroid.x, _centroid.y); }); @@ -99,10 +114,10 @@ void TouchInteraction::update(const std::vector& list, std::vector

positionVec3(), _camera->focusPositionVec3()); _vel.zoom += zoomFactor * _sensitivity.zoom; } - if (_interactionMode.pan) { // add local rotation velocity + if (_action.pan) { // add local rotation velocity _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; } - if (_interactionMode.roll) { // add global roll rotation velocity + if (_action.roll) { // add global roll rotation velocity double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = diff; @@ -116,26 +131,9 @@ void TouchInteraction::update(const std::vector& list, std::vector

maxX) - maxX = c.getX(); - if (c.getX() < minX) - minX = c.getX(); - if (c.getY() > maxY) - maxY = c.getY(); - if (c.getY() < minY) - minY = c.getY(); - } - double xRange = (maxX - minX) / list.size(); - double yRange = (maxY - minY) / list.size(); - //if (std::abs(rollFactor)/list.size() > 0.02) - _vel.localRoll += -rollFactor * _sensitivity.localRoll; + _vel.localRoll += -rollFactor * _sensitivity.localRoll; } - if (_interactionMode.pick) { // pick something in the scene as focus node + if (_action.pick) { // pick something in the scene as focus node } //default: @@ -161,26 +159,26 @@ void TouchInteraction::interpret(const std::vector& list, const std: if (list.size() == 1) { //if(!cursor.isMoving()) // pick - _interactionMode.rot = true; - _interactionMode.pinch = false; - _interactionMode.pan = false; - _interactionMode.roll = false; - _interactionMode.pick = false; + _action.rot = true; + _action.pinch = false; + _action.pan = false; + _action.roll = false; + _action.pick = false; } else { if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) { - _interactionMode.rot = false; - _interactionMode.pinch = false; - _interactionMode.pan = true; - _interactionMode.roll = false; - _interactionMode.pick = false; + _action.rot = false; + _action.pinch = false; + _action.pan = true; + _action.roll = false; + _action.pick = false; } else { - _interactionMode.rot = false; - _interactionMode.pinch = true; - _interactionMode.pan = false; - //_interactionMode.roll = true; - _interactionMode.pick = false; + _action.rot = false; + _action.pinch = true; + _action.pan = false; + //_action.roll = true; + _action.pick = false; double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; @@ -212,7 +210,7 @@ void TouchInteraction::interpret(const std::vector& list, const std: double xRange = (maxX - minX) / list.size(); double yRange = (maxY - minY) / list.size(); if (std::abs(rollFactor) / list.size() > 0.05) - _interactionMode.roll = true; + _action.roll = true; } } @@ -238,13 +236,16 @@ void TouchInteraction::step(double dt) { directionToCenter, normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion();; + dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); - double boundingSphere = _focusNode->boundingSphere().lengthf(); + double boundingSphere = _focusNode->boundingSphere().lengthd(); double minHeightAboveBoundingSphere = 1; dvec3 centerToBoundingSphere; + double distance = std::max(length(centerToCamera) - boundingSphere, 0.0); + _currentRadius = boundingSphere / std::max(distance * _projectionScaleFactor, 1.0); + { // Roll dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); localCamRot = localCamRot * camRollRot; @@ -324,18 +325,18 @@ void TouchInteraction::configSensitivities(double dist) { void TouchInteraction::decelerate() { _vel.zoom *= (1 - _friction.zoom); - _vel.globalRot *= (1 - _friction.globalRot); + _vel.globalRot *= (1 - 0.005); _vel.localRot *= (1 - _friction.localRot); _vel.globalRoll *= (1 - _friction.globalRoll); _vel.localRoll *= (1 - _friction.localRoll); } void TouchInteraction::clear() { - _interactionMode.rot = false; - _interactionMode.pinch = false; - _interactionMode.pan = false; - _interactionMode.roll = false; - _interactionMode.pick = false; + _action.rot = false; + _action.pinch = false; + _action.pan = false; + _action.roll = false; + _action.pick = false; } diff --git a/openspace.cfg b/openspace.cfg index 46ed8b5a0c..fb935d7514 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,7 +7,7 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, + SGCTConfig = sgct.config.single{}, -- Fullscreen mode --SGCTConfig = sgct.config.single{fullScreen=true}, @@ -26,7 +26,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/globebrowsing.scene", + Scene = "${SCENE}/default.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", From 31f0960c42d3aa065b4f3b82988bf0cd61296a82 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 29 Mar 2017 12:38:49 -0600 Subject: [PATCH 037/192] improvements to the interpret function so the interaction is more intuitive (now using an immobile finger as the centroid on roll) --- modules/touch/src/TouchInteraction.cpp | 81 ++++++++++++-------------- 1 file changed, 36 insertions(+), 45 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 70fa8396f4..cb1e96420b 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -58,10 +58,10 @@ TouchInteraction::TouchInteraction() _camera{ OsEng.interactionHandler().camera() }, _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, - _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction/4.0 }, + _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, _centroid{ glm::dvec3(0.0) }, _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.2 }, - _projectionScaleFactor{ 1.000004 }, + _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _directTouchMode{ false } { _origin.onChange([this]() { @@ -85,15 +85,19 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationQuaternion() * glm::dvec3(xCo, yCo, -1.0); glm::dvec3 camToCenter = _focusNode->worldPosition() - _camera->positionVec3(); - double dist = std::max(length(glm::cross(cursorInWorldSpace, camToCenter)) / length(cursorInWorldSpace) - _focusNode->boundingSphere().lengthd(), 0.0); - - std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(cursorInWorldSpace) << "\n"; + double dist = std::max(length(glm::cross(cursorInWorldSpace, camToCenter)) / glm::length(cursorInWorldSpace) - _focusNode->boundingSphere().lengthd(), 0.0); + // fix panning issue + /*std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(glm::normalize(cursorInWorldSpace)) + << "\nview: " << glm::to_string(_camera->viewDirectionWorldSpace()) + << "\ntoFocus: " << glm::to_string(glm::normalize(camToCenter)) << "\n\n";*/ + interpret(list, lastProcessed); if (!_action.rot) { _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); @@ -153,11 +157,24 @@ void TouchInteraction::interpret(const std::vector& list, const std: } TuioPoint point = lastProcessed.at(0).second; for (const Point& p : lastProcessed) { - dist += glm::length(glm::dvec2(p.second.getX(), p.second.getY()) - glm::dvec2(point.getX(), point.getY())); + lastDist += glm::length(glm::dvec2(p.second.getX(), p.second.getY()) - glm::dvec2(point.getX(), point.getY())); point = p.second; } + double betweenPoints; + + double minDiff = 1000; + int id = 0; + for (const TuioCursor& c : list) { + TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; + double diff = c.getX() - point.getX() + c.getY() - point.getY(); + if (std::abs(diff) < std::abs(minDiff)) { + minDiff = diff; + id = c.getSessionID(); + } + } if (list.size() == 1) { - //if(!cursor.isMoving()) // pick + if (!cursor.isMoving()) + std::cout << "cursor was moving but has now stopped\n"; _action.rot = true; _action.pinch = false; @@ -166,52 +183,26 @@ void TouchInteraction::interpret(const std::vector& list, const std: _action.pick = false; } else { - if (std::abs(dist - lastDist) / list.size() < 0.1 && list.size() == 2) { + if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 2) { _action.rot = false; _action.pinch = false; _action.pan = true; _action.roll = false; _action.pick = false; } + else if (list.size() > 2 && std::abs(minDiff) < 0.0008) { + _action.rot = false; + _action.pinch = false; + _action.pan = false; + _action.roll = true; + _action.pick = false; + } else { _action.rot = false; _action.pinch = true; _action.pan = false; - //_action.roll = true; + _action.roll = false; _action.pick = false; - - double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { - TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; - double res = diff; - double lastAngle = point.getAngle(_centroid.x, _centroid.y); - double currentAngle = c.getAngle(_centroid.x, _centroid.y); - if (lastAngle > currentAngle + 1.5*M_PI) - res += currentAngle + (2 * M_PI - lastAngle); - else if (currentAngle > lastAngle + 1.5*M_PI) - res += (2 * M_PI - currentAngle) + lastAngle; - else - res += currentAngle - lastAngle; - return res; - }); - double maxX = 0.0; - double minX = 1.0; - double maxY = 0.0; - double minY = 1.0; - for (const TuioCursor& c : list) { - if (c.getX() > maxX) - maxX = c.getX(); - if (c.getX() < minX) - minX = c.getX(); - if (c.getY() > maxY) - maxY = c.getY(); - if (c.getY() < minY) - minY = c.getY(); - } - double xRange = (maxX - minX) / list.size(); - double yRange = (maxY - minY) / list.size(); - if (std::abs(rollFactor) / list.size() > 0.05) - _action.roll = true; - } } } @@ -325,7 +316,7 @@ void TouchInteraction::configSensitivities(double dist) { void TouchInteraction::decelerate() { _vel.zoom *= (1 - _friction.zoom); - _vel.globalRot *= (1 - 0.005); + _vel.globalRot *= (1 - _friction.globalRot); _vel.localRot *= (1 - _friction.localRot); _vel.globalRoll *= (1 - _friction.globalRoll); _vel.localRoll *= (1 - _friction.localRoll); From 15450d9a9cd89a14d1d26028b05dd093b2f507fb Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 29 Mar 2017 15:16:05 -0600 Subject: [PATCH 038/192] all contact points are now traced into the scene to find a selection (distance calc still iffy with the rotation quat) --- modules/touch/src/TouchInteraction.cpp | 35 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index cb1e96420b..76191839b9 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -86,12 +86,27 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationQuaternion() * glm::dvec3(xCo, yCo, -1.0); - glm::dvec3 camToCenter = _focusNode->worldPosition() - _camera->positionVec3(); - double dist = std::max(length(glm::cross(cursorInWorldSpace, camToCenter)) / glm::length(cursorInWorldSpace) - _focusNode->boundingSphere().lengthd(), 0.0); + double aspectRatio = 1.777778; // static_cast(res.x/res.y); + glm::dquat camToWorldSpace = _camera->rotationQuaternion(); + glm::dvec3 camPos = _camera->positionVec3(); + std::vector> hitSelectables; + for (const TuioCursor& c : list) { + double xCo = 2 * (c.getX() - 0.5) * aspectRatio; + double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen + glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -1.0); + for (const SceneGraphNode* node : OsEng.renderEngine().scene()->allSceneGraphNodes()) { // should clean out to only use visible nodes that makes sense + double boundingSphere = node->boundingSphere().lengthd(); //should get current renderable's boundingSphere + glm::dvec3 camToSelectable = node->worldPosition() - camPos; // should get current renderable's position + double dist = std::max(length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere, 0.0); + if (dist == 0.0) { + // hit, push back cursor ID and selectable's position, need to clean list later to only have one a maximum of each id (delete pos further away in camera.z) + hitSelectables.push_back(std::make_pair(c.getSessionID(), node->worldPosition())); + std::cout << node->name() << " hit with cursor " << c.getSessionID() << ". World Pos: " << glm::to_string(node->worldPosition()) << "\n"; + } + } + + } + // fix panning issue /*std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(glm::normalize(cursorInWorldSpace)) @@ -146,7 +161,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, const std::vector& lastProcessed) { double dist = 0; double lastDist = 0; @@ -160,14 +174,17 @@ void TouchInteraction::interpret(const std::vector& list, const std: lastDist += glm::length(glm::dvec2(p.second.getX(), p.second.getY()) - glm::dvec2(point.getX(), point.getY())); point = p.second; } - double betweenPoints; double minDiff = 1000; int id = 0; for (const TuioCursor& c : list) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double diff = c.getX() - point.getX() + c.getY() - point.getY(); - if (std::abs(diff) < std::abs(minDiff)) { + if (!c.isMoving()) { + diff = minDiff = 0.0; + id = c.getSessionID(); + } + else if (std::abs(diff) < std::abs(minDiff)) { minDiff = diff; id = c.getSessionID(); } From 55157ab429fa31aee8a65a16b6d214200f8b9220 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 30 Mar 2017 13:05:10 -0600 Subject: [PATCH 039/192] Cleanup of TouchInteraction, selected can now only have one node per id --- modules/touch/include/TouchInteraction.h | 16 ++- modules/touch/src/TouchInteraction.cpp | 149 +++++++++++++---------- modules/touch/touchmodule.cpp | 4 +- 3 files changed, 96 insertions(+), 73 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index c41a132a72..753e3db0b0 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -83,7 +84,9 @@ class TouchInteraction : public properties::PropertyOwner ~TouchInteraction(); void update(const std::vector& list, std::vector& lastProcessed); + void trace(const std::vector& list); void interpret(const std::vector& list, const std::vector& lastProcessed); + void accelerate(const std::vector& list, const std::vector& lastProcessed); void step(double dt); void configSensitivities(double dist); void decelerate(); @@ -102,21 +105,24 @@ class TouchInteraction : public properties::PropertyOwner void setSensitivity(double sensitivity); private: + + // could be removed + double _baseSensitivity; + double _baseFriction; + double _minHeightFromSurface; + Camera* _camera; SceneGraphNode* _focusNode = nullptr; properties::StringProperty _origin; globebrowsing::RenderableGlobe* _globe; - bool _directTouchMode; double _projectionScaleFactor; double _currentRadius; - double _minHeightFromSurface; + std::vector> _selected; InteractionType _action; - double _baseSensitivity; - double _baseFriction; + glm::dvec3 _centroid; - VelocityStates _vel; ScaleFactor _friction; ScaleFactor _sensitivity; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 76191839b9..603948f136 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -60,7 +60,7 @@ TouchInteraction::TouchInteraction() _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, _centroid{ glm::dvec3(0.0) }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.2 }, + _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _directTouchMode{ false } { @@ -78,87 +78,58 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - TuioCursor cursor = list.at(0); - if (_currentRadius > 0.3) // good value to make any planet sufficiently large for direct-touch _directTouchMode = true; else _directTouchMode = false; - //glm::ivec2 res = OsEng.windowWrapper().currentWindowResolution(); - double aspectRatio = 1.777778; // static_cast(res.x/res.y); + trace(list); + interpret(list, lastProcessed); + accelerate(list, lastProcessed); +} + +void TouchInteraction::trace(const std::vector& list) { + //trim OsEng.renderEngine().scene()->allSceneGraphNodes() to only contain visible nodes that make sense + + glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + double aspectRatio = res.x/res.y; + std::cout << aspectRatio << ", " << glm::to_string(res) << "\n"; glm::dquat camToWorldSpace = _camera->rotationQuaternion(); glm::dvec3 camPos = _camera->positionVec3(); - std::vector> hitSelectables; + std::vector> newSelected; for (const TuioCursor& c : list) { double xCo = 2 * (c.getX() - 0.5) * aspectRatio; double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -1.0); - for (const SceneGraphNode* node : OsEng.renderEngine().scene()->allSceneGraphNodes()) { // should clean out to only use visible nodes that makes sense - double boundingSphere = node->boundingSphere().lengthd(); //should get current renderable's boundingSphere - glm::dvec3 camToSelectable = node->worldPosition() - camPos; // should get current renderable's position - double dist = std::max(length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere, 0.0); - if (dist == 0.0) { - // hit, push back cursor ID and selectable's position, need to clean list later to only have one a maximum of each id (delete pos further away in camera.z) - hitSelectables.push_back(std::make_pair(c.getSessionID(), node->worldPosition())); - std::cout << node->name() << " hit with cursor " << c.getSessionID() << ". World Pos: " << glm::to_string(node->worldPosition()) << "\n"; + for (SceneGraphNode* node : OsEng.renderEngine().scene()->allSceneGraphNodes()) { + double boundingSphere = node->boundingSphere().lengthd(); + glm::dvec3 camToSelectable = node->worldPosition() - camPos; + int id = c.getSessionID(); + double dist = length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere; + if (dist < 0.0) { + auto found = find_if(newSelected.begin(), newSelected.end(), [id](std::pair p) { return p.first == id; }); + if (found != newSelected.end()) { + double oldNodeDist = glm::length(found->second->worldPosition() - camPos); + if (glm::length(camToSelectable) < oldNodeDist) { // new node is closer, remove added node and add the new one instead + newSelected.pop_back(); + newSelected.push_back(std::make_pair(id, node)); + } + } + else + newSelected.push_back(std::make_pair(id, node)); } } - } - - // fix panning issue - - /*std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(glm::normalize(cursorInWorldSpace)) - << "\nview: " << glm::to_string(_camera->viewDirectionWorldSpace()) - << "\ntoFocus: " << glm::to_string(glm::normalize(camToCenter)) << "\n\n";*/ - interpret(list, lastProcessed); - if (!_action.rot) { - _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); - _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - } - - if (_action.rot) { // add rotation velocity - _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; - } - if (_action.pinch) { // add zooming velocity - double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { - return d + c.getDistance(_centroid.x, _centroid.y); - }); - double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { - return d + p.second.getDistance(_centroid.x, _centroid.y); - }); - - double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); - _vel.zoom += zoomFactor * _sensitivity.zoom; - } - if (_action.pan) { // add local rotation velocity - _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; - } - if (_action.roll) { // add global roll rotation velocity - double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { - TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; - double res = diff; - double lastAngle = point.getAngle(_centroid.x, _centroid.y); - double currentAngle = c.getAngle(_centroid.x, _centroid.y); - if (lastAngle > currentAngle + 1.5*M_PI) - res += currentAngle + (2*M_PI - lastAngle); - else if (currentAngle > lastAngle + 1.5*M_PI) - res += (2*M_PI - currentAngle) + lastAngle; - else - res += currentAngle - lastAngle; - return res; - }); - _vel.localRoll += -rollFactor * _sensitivity.localRoll; - } - if (_action.pick) { // pick something in the scene as focus node - - } - //default: - //LINFO("Couldn't interpret touch input" << "\n"); - //} + //debugging + for (auto it : newSelected) + std::cout << it.second->name() << " hit with cursor " << it.first << ". World Pos: " << glm::to_string(it.second->worldPosition()) << "\n"; + /*std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(glm::normalize(cursorInWorldSpace)) + << "\nview: " << glm::to_string(_camera->viewDirectionWorldSpace()) + << "\ntoFocus: " << glm::to_string(glm::normalize(camToCenter)) << "\n\n";*/ + + _selected = newSelected; // might want to remember what was selected last frame } void TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { @@ -224,6 +195,51 @@ void TouchInteraction::interpret(const std::vector& list, const std: } } +void TouchInteraction::accelerate(const std::vector& list, const std::vector& lastProcessed) { + TuioCursor cursor = list.at(0); + if (!_action.rot) { + _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + } + + if (_action.rot) { // add rotation velocity + _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; + } + if (_action.pinch) { // add zooming velocity + double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { + return d + c.getDistance(_centroid.x, _centroid.y); + }); + double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { + return d + p.second.getDistance(_centroid.x, _centroid.y); + }); + + double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); + _vel.zoom += zoomFactor * _sensitivity.zoom; + } + if (_action.pan) { // add local rotation velocity + _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; + } + if (_action.roll) { // add global roll rotation velocity + double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { + TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; + double res = diff; + double lastAngle = point.getAngle(_centroid.x, _centroid.y); + double currentAngle = c.getAngle(_centroid.x, _centroid.y); + if (lastAngle > currentAngle + 1.5*M_PI) + res += currentAngle + (2 * M_PI - lastAngle); + else if (currentAngle > lastAngle + 1.5*M_PI) + res += (2 * M_PI - currentAngle) + lastAngle; + else + res += currentAngle - lastAngle; + return res; + }); + _vel.localRoll += -rollFactor * _sensitivity.localRoll; + } + if (_action.pick) { // pick something in the scene as focus node + + } +} + void TouchInteraction::step(double dt) { using namespace glm; @@ -307,7 +323,6 @@ void TouchInteraction::step(double dt) { } } - void TouchInteraction::configSensitivities(double dist) { // Configurates sensitivities to appropriate values when the camera is close to the focus node. std::shared_ptr gbim = diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 92db5c9679..ca9cc58f03 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -76,7 +76,9 @@ bool TouchModule::gotNewInput() { if (list.size() == lastProcessed.size() && list.size() > 0) { bool newInput = true; for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { - if (p.second.getTuioTime().getTotalMilliseconds() == find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; })->getPath().back().getTuioTime().getTotalMilliseconds()) + std::vector::iterator cursor = find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); + double now = cursor->getPath().back().getTuioTime().getTotalMilliseconds(); + if (p.second.getTuioTime().getTotalMilliseconds() == now || !cursor->isMoving()) newInput = false; }); return newInput; From a5873c3002078bde02f8488fed9f7b8743a3b901 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 30 Mar 2017 16:28:51 -0600 Subject: [PATCH 040/192] tracing now works correctly with panning, there's an issue when OpenSpace aspect Ratio is not the same as the touch interface aspect ratio --- modules/touch/src/TouchInteraction.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 603948f136..18f20e801c 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -89,21 +89,29 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list) { - //trim OsEng.renderEngine().scene()->allSceneGraphNodes() to only contain visible nodes that make sense + + //trim list to only contain visible nodes that make sense + std::string selectables[30] = { "Sun", "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", + "Moon", "Titan", "Rhea", "Mimas", "Iapetus", "Enceladus", "Dione", "Io", "Ganymede", "Europa", + "Callisto", "NewHorizons", "Styx", "Nix", "Kerberos", "Hydra", "Charon", "Tethys", "OsirisRex", "Bennu" }; + std::vector selectableNodes; + for (SceneGraphNode* node : OsEng.renderEngine().scene()->allSceneGraphNodes()) + for (std::string name : selectables) + if (node->name() == name) + selectableNodes.push_back(node); glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); double aspectRatio = res.x/res.y; - std::cout << aspectRatio << ", " << glm::to_string(res) << "\n"; glm::dquat camToWorldSpace = _camera->rotationQuaternion(); glm::dvec3 camPos = _camera->positionVec3(); std::vector> newSelected; for (const TuioCursor& c : list) { double xCo = 2 * (c.getX() - 0.5) * aspectRatio; double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen - glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -1.0); - for (SceneGraphNode* node : OsEng.renderEngine().scene()->allSceneGraphNodes()) { + glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -3.2596558); + for (SceneGraphNode* node : selectableNodes) { double boundingSphere = node->boundingSphere().lengthd(); - glm::dvec3 camToSelectable = node->worldPosition() - camPos; + glm::dvec3 camToSelectable = camPos - node->worldPosition(); int id = c.getSessionID(); double dist = length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere; if (dist < 0.0) { @@ -128,7 +136,6 @@ void TouchInteraction::trace(const std::vector& list) { << "\nview: " << glm::to_string(_camera->viewDirectionWorldSpace()) << "\ntoFocus: " << glm::to_string(glm::normalize(camToCenter)) << "\n\n";*/ - _selected = newSelected; // might want to remember what was selected last frame } From 7b23c17b10d4ca30151a4ecc1797386d17486fd7 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 31 Mar 2017 14:39:05 -0600 Subject: [PATCH 041/192] TuioEar can now detect a tap, implemented picking feature. If a selectable node is tapped at that is set as the new focusNode and the camera does a panning to that direction. If not will the camera zoom in towards the focusNode --- modules/touch/include/TuioEar.h | 9 +++++- modules/touch/src/TouchInteraction.cpp | 43 ++++++++++++++++++++------ modules/touch/src/TuioEar.cpp | 22 +++++++++++-- modules/touch/touchmodule.cpp | 9 +++++- modules/touch/touchmodule.h | 1 - 5 files changed, 69 insertions(+), 15 deletions(-) diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index 9a13a0a19a..ef90fb3056 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -65,15 +65,22 @@ class TuioEar : public TUIO::TuioListener { void refresh(TUIO::TuioTime frameTime); std::vector getInput(); + bool tap(); + TUIO::TuioCursor getTap(); void clearInput(); private: + bool _tap; + TUIO::TuioCursor _tapCo = TUIO::TuioCursor(-1, -1, -1.0f, -1.0f); + std::mutex _mx; + TUIO::TuioClient *_tuioClient; TUIO::OscReceiver *_oscReceiver; + std::vector _list; std::vector _removeList; - std::mutex _mx; + }; #endif // __OPENSPACE_MODULE_TOUCH___TOUCHWRAPPER___H__ diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 18f20e801c..e791ff923a 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -84,6 +84,8 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, const std: } } if (list.size() == 1) { - if (!cursor.isMoving()) - std::cout << "cursor was moving but has now stopped\n"; - - _action.rot = true; - _action.pinch = false; - _action.pan = false; - _action.roll = false; - _action.pick = false; + //std::cout << "Tap: " << cursor.getSessionID() << ". (" << cursor.getX() << "," << cursor.getY() << "), Speed: " + //<< cursor.getMotionSpeed() << ", Path: " << cursor.getPath().size() << ", Time: " << cursor.getPath().back().getTuioTime().getTotalMilliseconds() + //<< ", lastTime: " << lastProcessed.at(0).second.getTuioTime().getTotalMilliseconds() << "\n"; + if (!cursor.isMoving() && cursor.getPath().size() == 1) { // tap + _action.rot = false; + _action.pinch = false; + _action.pan = false; + _action.roll = false; + _action.pick = true; + } + else { + _action.rot = true; + _action.pinch = false; + _action.pan = false; + _action.roll = false; + _action.pick = false; + } } else { if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 2) { @@ -204,7 +215,7 @@ void TouchInteraction::interpret(const std::vector& list, const std: void TouchInteraction::accelerate(const std::vector& list, const std::vector& lastProcessed) { TuioCursor cursor = list.at(0); - if (!_action.rot) { + if (!_action.rot || !_action.pick) { _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); } @@ -243,7 +254,19 @@ void TouchInteraction::accelerate(const std::vector& list, const std _vel.localRoll += -rollFactor * _sensitivity.localRoll; } if (_action.pick) { // pick something in the scene as focus node - + if (_selected.size() == 1 && _selected.at(0).second != _focusNode) { + _focusNode = _selected.at(0).second; // rotate camera to look at new focus + OsEng.interactionHandler().setFocusNode(_focusNode); + glm::dvec3 camToFocus = glm::normalize(_camera->positionVec3() - _focusNode->worldPosition()); + double angleX = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, _camera->lookUpVectorWorldSpace()); + double angleY = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * glm::dvec3(1,0,0))); + std::cout << "x: " << angleX << ", y: " << angleY << "\n"; + _vel.localRot = 3.0 * _sensitivity.localRot * glm::dvec2(-angleX, -angleY); + } + else { + _vel.zoom = _sensitivity.zoom * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); + } + } } diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 8850bef9af..68b6994c74 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -48,7 +48,6 @@ void TuioEar::removeTuioObject(TuioObject *tobj) { } void TuioEar::addTuioCursor(TuioCursor *tcur) { _mx.lock(); - // find same id in _list if it exists in _removeList (new input with same ID as a previously stored) int i = tcur->getSessionID(); std::vector::iterator foundID = std::find_if( @@ -74,6 +73,7 @@ void TuioEar::addTuioCursor(TuioCursor *tcur) { void TuioEar::updateTuioCursor(TuioCursor *tcur) { _mx.lock(); + _tap = false; int i = tcur->getSessionID(); std::find_if( _list.begin(), @@ -87,8 +87,12 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { // save id to be removed and remove it in clearInput void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); + if (tcur->getPath().size() < 3 && tcur->getMotionSpeed() < 0.05) { + _tapCo = TuioCursor(*tcur); + _tap = true; + } + _removeList.push_back(tcur->getSessionID()); - //LINFO("To be removed: " << _removeFromList.size() << "\n"); _mx.unlock(); } @@ -105,6 +109,20 @@ std::vector TuioEar::getInput() { return _list; } +bool TuioEar::tap() { + std::lock_guard lock(_mx); + if (_tap) { + _tap = false; + return !_tap; + } + else + return _tap; +} + +TuioCursor TuioEar::getTap() { + return _tapCo; +} + void TuioEar::clearInput() { _mx.lock(); _list.erase( diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index ca9cc58f03..b6473446e1 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -71,8 +71,15 @@ bool TouchModule::gotNewInput() { ) == list.end(); }), lastProcessed.end()); - // Return true if we got new input + // Tap + if (list.size() == 0 && lastProcessed.size() == 0 && ear->tap()) { + TuioCursor c = ear->getTap(); + list.push_back(c); + lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); + return true; + } + // Return true if we got new input if (list.size() == lastProcessed.size() && list.size() > 0) { bool newInput = true; for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index e68deffc42..6fbf907b26 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -41,7 +41,6 @@ public: bool gotNewInput(); - //TouchInteraction touch; TuioEar* ear; From c6b8917d4b2751452d6c752f849c0e9254e7f120 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 31 Mar 2017 16:27:06 -0600 Subject: [PATCH 042/192] rotation correction when selecting new node --- modules/touch/src/TouchInteraction.cpp | 4 ++-- modules/touch/src/TuioEar.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index e791ff923a..580e1cbf99 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -258,10 +258,10 @@ void TouchInteraction::accelerate(const std::vector& list, const std _focusNode = _selected.at(0).second; // rotate camera to look at new focus OsEng.interactionHandler().setFocusNode(_focusNode); glm::dvec3 camToFocus = glm::normalize(_camera->positionVec3() - _focusNode->worldPosition()); - double angleX = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, _camera->lookUpVectorWorldSpace()); + double angleX = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * _camera->lookUpVectorWorldSpace())); double angleY = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * glm::dvec3(1,0,0))); std::cout << "x: " << angleX << ", y: " << angleY << "\n"; - _vel.localRot = 3.0 * _sensitivity.localRot * glm::dvec2(-angleX, -angleY); + _vel.localRot = _sensitivity.localRot * glm::dvec2(-angleX, -angleY); } else { _vel.zoom = _sensitivity.zoom * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 68b6994c74..6fbf07b7c1 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -87,7 +87,7 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { // save id to be removed and remove it in clearInput void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); - if (tcur->getPath().size() < 3 && tcur->getMotionSpeed() < 0.05) { + if (tcur->getPath().size() < 3 && tcur->getMotionSpeed() < 0.03) { _tapCo = TuioCursor(*tcur); _tap = true; } From 4416707931c07746ad4cba5675acf26d4ac0d835 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 4 Apr 2017 13:36:35 -0600 Subject: [PATCH 043/192] find traced rays intersection point on boundingsphere for direct touch interaction --- modules/touch/src/TouchInteraction.cpp | 23 +++++++++++++++++------ openspace.cfg | 4 ++-- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 580e1cbf99..8b2e90c64b 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -111,12 +111,13 @@ void TouchInteraction::trace(const std::vector& list) { double xCo = 2 * (c.getX() - 0.5) * aspectRatio; double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -3.2596558); + glm::dvec3 normCursor = glm::normalize(cursorInWorldSpace); for (SceneGraphNode* node : selectableNodes) { double boundingSphere = node->boundingSphere().lengthd(); - glm::dvec3 camToSelectable = camPos - node->worldPosition(); + glm::dvec3 camToSelectable = node->worldPosition() - camPos; int id = c.getSessionID(); double dist = length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere; - if (dist < 0.0) { + if (dist <= 0.0) { auto found = find_if(newSelected.begin(), newSelected.end(), [id](std::pair p) { return p.first == id; }); if (found != newSelected.end()) { double oldNodeDist = glm::length(found->second->worldPosition() - camPos); @@ -127,6 +128,16 @@ void TouchInteraction::trace(const std::vector& list) { } else newSelected.push_back(std::make_pair(id, node)); + + // finds intersection point between boundingsphere and line in world coordinates, assumes line direction is normalized + double d = glm::dot(normCursor, camToSelectable); + double root = std::sqrt((std::pow(boundingSphere, 2) - glm::dot(camToSelectable, camToSelectable)) + std::pow(d, 2)); + if (root > 0) // two intersection points (take the closest one) + d -= sqrt(root); + glm::dvec3 intersectionPoint = camPos + d * normCursor; + //double d2 = d + sqrt(root); + //glm::dvec3 intersectionPoint2 = camPos + d2 * normCursor; + //std::cout << root << ", " << glm::to_string(intersectionPoint) << ", " << glm::to_string(intersectionPoint2) << "\n"; } } } @@ -231,7 +242,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std return d + p.second.getDistance(_centroid.x, _centroid.y); }); - double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); + double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); // make into log space instead _vel.zoom += zoomFactor * _sensitivity.zoom; } if (_action.pan) { // add local rotation velocity @@ -256,8 +267,8 @@ void TouchInteraction::accelerate(const std::vector& list, const std if (_action.pick) { // pick something in the scene as focus node if (_selected.size() == 1 && _selected.at(0).second != _focusNode) { _focusNode = _selected.at(0).second; // rotate camera to look at new focus - OsEng.interactionHandler().setFocusNode(_focusNode); - glm::dvec3 camToFocus = glm::normalize(_camera->positionVec3() - _focusNode->worldPosition()); + OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode + glm::dvec3 camToFocus = glm::normalize(_focusNode->worldPosition() - _camera->positionVec3()); double angleX = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * _camera->lookUpVectorWorldSpace())); double angleY = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * glm::dvec3(1,0,0))); std::cout << "x: " << angleX << ", y: " << angleY << "\n"; @@ -273,7 +284,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std void TouchInteraction::step(double dt) { using namespace glm; - setFocusNode(OsEng.interactionHandler().focusNode()); + setFocusNode(OsEng.interactionHandler().focusNode()); // since setFocusNode cant be called directly (TouchInteraction not a subclass of InteractionMode) if (_focusNode) { // Create variables from current state dvec3 camPos = _camera->positionVec3(); diff --git a/openspace.cfg b/openspace.cfg index fb935d7514..ceceb5af30 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -13,7 +13,7 @@ return { --SGCTConfig = sgct.config.single{fullScreen=true}, -- A regular 1920x1080 window - -- SGCTConfig = sgct.config.single{1920, 1080}, + -- SGCTConfig = sgct.config.single{1920, 1080, border=false}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, @@ -26,7 +26,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/default.scene", + Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", From cbc8a2cb7e12ad769b689232a3986d5599a210c7 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 6 Apr 2017 14:06:40 -0600 Subject: [PATCH 044/192] touch is more snappy, nice --- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 69 ++++++++++++++---------- modules/touch/src/TuioEar.cpp | 5 +- modules/touch/touchmodule.cpp | 5 +- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 753e3db0b0..d493fbe99e 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -91,7 +91,7 @@ class TouchInteraction : public properties::PropertyOwner void configSensitivities(double dist); void decelerate(); void clear(); - + void tap(); // Get & Setters Camera* getCamera(); @@ -116,6 +116,7 @@ class TouchInteraction : public properties::PropertyOwner properties::StringProperty _origin; globebrowsing::RenderableGlobe* _globe; + bool _tap; bool _directTouchMode; double _projectionScaleFactor; double _currentRadius; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 8b2e90c64b..8e876a32a0 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -62,7 +62,7 @@ TouchInteraction::TouchInteraction() _centroid{ glm::dvec3(0.0) }, _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _directTouchMode{ false } + _directTouchMode{ false }, _tap{ false } { _origin.onChange([this]() { SceneGraphNode* node = sceneGraphNode(_origin.value()); @@ -111,7 +111,7 @@ void TouchInteraction::trace(const std::vector& list) { double xCo = 2 * (c.getX() - 0.5) * aspectRatio; double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -3.2596558); - glm::dvec3 normCursor = glm::normalize(cursorInWorldSpace); + glm::dvec3 raytrace = glm::normalize(cursorInWorldSpace); for (SceneGraphNode* node : selectableNodes) { double boundingSphere = node->boundingSphere().lengthd(); glm::dvec3 camToSelectable = node->worldPosition() - camPos; @@ -130,14 +130,26 @@ void TouchInteraction::trace(const std::vector& list) { newSelected.push_back(std::make_pair(id, node)); // finds intersection point between boundingsphere and line in world coordinates, assumes line direction is normalized - double d = glm::dot(normCursor, camToSelectable); - double root = std::sqrt((std::pow(boundingSphere, 2) - glm::dot(camToSelectable, camToSelectable)) + std::pow(d, 2)); + double d = glm::dot(raytrace, camToSelectable); + double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; if (root > 0) // two intersection points (take the closest one) d -= sqrt(root); - glm::dvec3 intersectionPoint = camPos + d * normCursor; + glm::dvec3 intersectionPoint = camPos + d * raytrace; //double d2 = d + sqrt(root); - //glm::dvec3 intersectionPoint2 = camPos + d2 * normCursor; - //std::cout << root << ", " << glm::to_string(intersectionPoint) << ", " << glm::to_string(intersectionPoint2) << "\n"; + //glm::dvec3 intersectionPoint2 = camPos + d2 * raytrace; + //std::cout << root << ", " << glm::to_string(intersectionPoint) /*<< ", " << glm::to_string(intersectionPoint2)*/ << "\n"; + + std::cout << glm::to_string(raytrace) << "\n"; + + + glm::dvec3 modelVector = node->rotationMatrix() * glm::dvec3(1.0, 0.0, 0.0); + // assume raytrace is constant +#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED + // in this case raytrace dir in world space differs as we follow the focus nodes rotation with the camera +#endif + + // f(theta, phi, v) = matrix * modelVector = surfacepointinmodelview + } } } @@ -180,24 +192,20 @@ void TouchInteraction::interpret(const std::vector& list, const std: id = c.getSessionID(); } } - if (list.size() == 1) { - //std::cout << "Tap: " << cursor.getSessionID() << ". (" << cursor.getX() << "," << cursor.getY() << "), Speed: " - //<< cursor.getMotionSpeed() << ", Path: " << cursor.getPath().size() << ", Time: " << cursor.getPath().back().getTuioTime().getTotalMilliseconds() - //<< ", lastTime: " << lastProcessed.at(0).second.getTuioTime().getTotalMilliseconds() << "\n"; - if (!cursor.isMoving() && cursor.getPath().size() == 1) { // tap - _action.rot = false; - _action.pinch = false; - _action.pan = false; - _action.roll = false; - _action.pick = true; - } - else { - _action.rot = true; - _action.pinch = false; - _action.pan = false; - _action.roll = false; - _action.pick = false; - } + if (_tap) { + _tap = false; + _action.rot = false; + _action.pinch = false; + _action.pan = false; + _action.roll = false; + _action.pick = true; + } + else if (list.size() == 1) { + _action.rot = true; + _action.pinch = false; + _action.pan = false; + _action.roll = false; + _action.pick = false; } else { if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 2) { @@ -271,11 +279,11 @@ void TouchInteraction::accelerate(const std::vector& list, const std glm::dvec3 camToFocus = glm::normalize(_focusNode->worldPosition() - _camera->positionVec3()); double angleX = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * _camera->lookUpVectorWorldSpace())); double angleY = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * glm::dvec3(1,0,0))); - std::cout << "x: " << angleX << ", y: " << angleY << "\n"; + //std::cout << "x: " << angleX << ", y: " << angleY << "\n"; _vel.localRot = _sensitivity.localRot * glm::dvec2(-angleX, -angleY); } else { - _vel.zoom = _sensitivity.zoom * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); + _vel.zoom = _sensitivity.zoom * (glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere().lengthd()); } } @@ -376,6 +384,10 @@ void TouchInteraction::configSensitivities(double dist) { //_sensitivity.globalRoll = 0.1; //_sensitivity.localRoll = 0.1; } + else if (dist < close) { + _sensitivity.zoom = 2.0 * std::max(dist, 100.0) / close; + _sensitivity.globalRot = 0.1 * std::max(dist, 100.0) / close; + } else { _sensitivity.zoom = 2.0; _sensitivity.globalRot = 0.1; @@ -403,6 +415,9 @@ void TouchInteraction::clear() { _action.pick = false; } +void TouchInteraction::tap() { + _tap = true; +} // Getters Camera* TouchInteraction::getCamera() { diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 6fbf07b7c1..d04a2c3638 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -48,6 +48,7 @@ void TuioEar::removeTuioObject(TuioObject *tobj) { } void TuioEar::addTuioCursor(TuioCursor *tcur) { _mx.lock(); + _tap = false; // find same id in _list if it exists in _removeList (new input with same ID as a previously stored) int i = tcur->getSessionID(); std::vector::iterator foundID = std::find_if( @@ -87,7 +88,7 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { // save id to be removed and remove it in clearInput void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); - if (tcur->getPath().size() < 3 && tcur->getMotionSpeed() < 0.03) { + if (tcur->getPath().size() < 4 && tcur->getMotionSpeed() < 0.03) { _tapCo = TuioCursor(*tcur); _tap = true; } @@ -102,7 +103,7 @@ void TuioEar::updateTuioBlob(TuioBlob *tblb) { } void TuioEar::removeTuioBlob(TuioBlob *tblb) { } -void TuioEar::refresh(TuioTime frameTime) { } // about every 15ms on TuioPad app +void TuioEar::refresh(TuioTime frameTime) { } // about every 15ms std::vector TuioEar::getInput() { std::lock_guard lock(_mx); diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index b6473446e1..22a3b1e96a 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -76,6 +76,7 @@ bool TouchModule::gotNewInput() { TuioCursor c = ear->getTap(); list.push_back(c); lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); + touch->tap(); return true; } @@ -85,7 +86,9 @@ bool TouchModule::gotNewInput() { for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { std::vector::iterator cursor = find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); double now = cursor->getPath().back().getTuioTime().getTotalMilliseconds(); - if (p.second.getTuioTime().getTotalMilliseconds() == now || !cursor->isMoving()) + if (!cursor->isMoving()) + newInput = true; + else if (p.second.getTuioTime().getTotalMilliseconds() == now) newInput = false; }); return newInput; From 31e175232a2d2020070ff87900204fa9a509ca67 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 6 Apr 2017 15:16:25 -0600 Subject: [PATCH 045/192] the point on the surface of a body can now be described in spherical coordinates --- modules/touch/include/TouchInteraction.h | 7 +++- modules/touch/src/TouchInteraction.cpp | 49 ++++++++++-------------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index d493fbe99e..9e24216e73 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -74,6 +74,11 @@ struct InteractionType { bool roll; bool pick; }; +struct SelectedBody { + int id; + SceneGraphNode* node; + glm::dvec2 coordinates; +}; using Point = std::pair; @@ -120,7 +125,7 @@ class TouchInteraction : public properties::PropertyOwner bool _directTouchMode; double _projectionScaleFactor; double _currentRadius; - std::vector> _selected; + std::vector _selected; InteractionType _action; glm::dvec3 _centroid; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 8e876a32a0..a7844ee19e 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -43,6 +43,7 @@ #include #endif +#include #include namespace { @@ -106,7 +107,7 @@ void TouchInteraction::trace(const std::vector& list) { double aspectRatio = res.x/res.y; glm::dquat camToWorldSpace = _camera->rotationQuaternion(); glm::dvec3 camPos = _camera->positionVec3(); - std::vector> newSelected; + std::vector newSelected; for (const TuioCursor& c : list) { double xCo = 2 * (c.getX() - 0.5) * aspectRatio; double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen @@ -118,45 +119,35 @@ void TouchInteraction::trace(const std::vector& list) { int id = c.getSessionID(); double dist = length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere; if (dist <= 0.0) { - auto found = find_if(newSelected.begin(), newSelected.end(), [id](std::pair p) { return p.first == id; }); - if (found != newSelected.end()) { - double oldNodeDist = glm::length(found->second->worldPosition() - camPos); - if (glm::length(camToSelectable) < oldNodeDist) { // new node is closer, remove added node and add the new one instead - newSelected.pop_back(); - newSelected.push_back(std::make_pair(id, node)); - } - } - else - newSelected.push_back(std::make_pair(id, node)); - // finds intersection point between boundingsphere and line in world coordinates, assumes line direction is normalized double d = glm::dot(raytrace, camToSelectable); double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; if (root > 0) // two intersection points (take the closest one) d -= sqrt(root); glm::dvec3 intersectionPoint = camPos + d * raytrace; - //double d2 = d + sqrt(root); - //glm::dvec3 intersectionPoint2 = camPos + d2 * raytrace; - //std::cout << root << ", " << glm::to_string(intersectionPoint) /*<< ", " << glm::to_string(intersectionPoint2)*/ << "\n"; - - std::cout << glm::to_string(raytrace) << "\n"; - - - glm::dvec3 modelVector = node->rotationMatrix() * glm::dvec3(1.0, 0.0, 0.0); - // assume raytrace is constant -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - // in this case raytrace dir in world space differs as we follow the focus nodes rotation with the camera -#endif - - // f(theta, phi, v) = matrix * modelVector = surfacepointinmodelview + glm::dvec3 pointInModelView = glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition()); + double theta = atan(pointInModelView.y / pointInModelView.x); + double phi = atan(glm::length(glm::dvec2(pointInModelView.x, pointInModelView.y)) / pointInModelView.z); // spherical coordinates for point on surface + // Add id, node and surface coordinates to the selected list + auto found = find_if(newSelected.begin(), newSelected.end(), [id](SelectedBody s) { return s.id == id; }); + if (found != newSelected.end()) { + double oldNodeDist = glm::length(found->node->worldPosition() - camPos); + if (glm::length(camToSelectable) < oldNodeDist) { // new node is closer, remove added node and add the new one instead + newSelected.pop_back(); + newSelected.push_back({ id, node, glm::dvec2(theta, phi) }); + } + } + else { + newSelected.push_back({ id, node, glm::dvec2(theta, phi) }); + } } } } //debugging for (auto it : newSelected) - std::cout << it.second->name() << " hit with cursor " << it.first << ". World Pos: " << glm::to_string(it.second->worldPosition()) << "\n"; + std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; /*std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(glm::normalize(cursorInWorldSpace)) << "\nview: " << glm::to_string(_camera->viewDirectionWorldSpace()) << "\ntoFocus: " << glm::to_string(glm::normalize(camToCenter)) << "\n\n";*/ @@ -273,8 +264,8 @@ void TouchInteraction::accelerate(const std::vector& list, const std _vel.localRoll += -rollFactor * _sensitivity.localRoll; } if (_action.pick) { // pick something in the scene as focus node - if (_selected.size() == 1 && _selected.at(0).second != _focusNode) { - _focusNode = _selected.at(0).second; // rotate camera to look at new focus + if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { + _focusNode = _selected.at(0).node; // rotate camera to look at new focus OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode glm::dvec3 camToFocus = glm::normalize(_focusNode->worldPosition() - _camera->positionVec3()); double angleX = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * _camera->lookUpVectorWorldSpace())); From 1c1570e8549ab28cd25e476d436414c947020f72 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 7 Apr 2017 11:12:02 -0600 Subject: [PATCH 046/192] defined a function to go from modelview to screen space view, comments on step-by-step method for the direct-touch solution --- modules/touch/include/TouchInteraction.h | 4 +- modules/touch/src/TouchInteraction.cpp | 50 ++++++++++++++++++++---- openspace.cfg | 2 +- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 9e24216e73..5025df0673 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -77,7 +77,7 @@ struct InteractionType { struct SelectedBody { int id; SceneGraphNode* node; - glm::dvec2 coordinates; + glm::dvec3 coordinates; }; using Point = std::pair; @@ -95,6 +95,7 @@ class TouchInteraction : public properties::PropertyOwner void step(double dt); void configSensitivities(double dist); void decelerate(); + glm::dvec3 TouchInteraction::modelToScreenSpace(SelectedBody sb); void clear(); void tap(); @@ -126,6 +127,7 @@ class TouchInteraction : public properties::PropertyOwner double _projectionScaleFactor; double _currentRadius; std::vector _selected; + std::vector _lastSelected; InteractionType _action; glm::dvec3 _centroid; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index a7844ee19e..07617d7b5e 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -126,8 +126,9 @@ void TouchInteraction::trace(const std::vector& list) { d -= sqrt(root); glm::dvec3 intersectionPoint = camPos + d * raytrace; glm::dvec3 pointInModelView = glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition()); + // spherical coordinates for point on surface, maybe not required double theta = atan(pointInModelView.y / pointInModelView.x); - double phi = atan(glm::length(glm::dvec2(pointInModelView.x, pointInModelView.y)) / pointInModelView.z); // spherical coordinates for point on surface + double phi = atan(glm::length(glm::dvec2(pointInModelView.x, pointInModelView.y)) / pointInModelView.z); // Add id, node and surface coordinates to the selected list auto found = find_if(newSelected.begin(), newSelected.end(), [id](SelectedBody s) { return s.id == id; }); @@ -135,24 +136,47 @@ void TouchInteraction::trace(const std::vector& list) { double oldNodeDist = glm::length(found->node->worldPosition() - camPos); if (glm::length(camToSelectable) < oldNodeDist) { // new node is closer, remove added node and add the new one instead newSelected.pop_back(); - newSelected.push_back({ id, node, glm::dvec2(theta, phi) }); + newSelected.push_back({ id, node, pointInModelView }); } } else { - newSelected.push_back({ id, node, glm::dvec2(theta, phi) }); + newSelected.push_back({ id, node, pointInModelView }); } } } + } + /* + Direct-touch: + 1, we have the touched position on the surface in spherical coordinates + 2, we get new input on new pos + 3, move camera so _selected.coordinates == new pos, cant overwrite _selected then + + Paper: + position in screen-space: p = s(x,q) = h(PM(q)x) + h = combinedViewMatrix + P = projectionmatrix + M(q) = parameterized matrix by the vector q which maps x into worldspace, most likely the product of several matrices which are + parameterized by the transform values (e.g., rotation, scaling, translation, etc.) + x = position in modelview + + minimize error E = sum( ||s(xi,q)-pi||^2 ) (distance between last point p and current x in screen-space) + q is the rotation/translation that is done on the object to match the equation. How do we translate that to camera rot/trans? + */ //debugging - for (auto it : newSelected) + for (auto it : newSelected) { std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; - /*std::cout << "Dist: " << dist << ", Ray: " << glm::to_string(glm::normalize(cursorInWorldSpace)) - << "\nview: " << glm::to_string(_camera->viewDirectionWorldSpace()) - << "\ntoFocus: " << glm::to_string(glm::normalize(camToCenter)) << "\n\n";*/ + glm::dvec3 screenspace = modelToScreenSpace(it); + } + // 1, check if _selected is initialized + // 2, find M(q) that transforms _selected.it->coordinates to newSelected.it->coordinates + // 3, find difference in newSelected and _selected in screen-space + // 4, calculate minimum error - _selected = newSelected; // might want to remember what was selected last frame + + _lastSelected = _selected; + _selected = newSelected; } void TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { @@ -363,6 +387,13 @@ void TouchInteraction::step(double dt) { } } + +glm::dvec3 TouchInteraction::modelToScreenSpace(SelectedBody sb) { + glm::dvec3 backToScreenSpace = glm::inverse(_camera->rotationQuaternion()) + * glm::normalize(((sb.node->rotationMatrix() * sb.coordinates) + sb.node->worldPosition() - _camera->positionVec3())); + return (backToScreenSpace * (-3.2596558 / backToScreenSpace.z)); +} + void TouchInteraction::configSensitivities(double dist) { // Configurates sensitivities to appropriate values when the camera is close to the focus node. std::shared_ptr gbim = @@ -404,6 +435,9 @@ void TouchInteraction::clear() { _action.pan = false; _action.roll = false; _action.pick = false; + + _selected.clear(); // should clear if no longer have a direct-touch input + _lastSelected.clear(); } void TouchInteraction::tap() { diff --git a/openspace.cfg b/openspace.cfg index ceceb5af30..c4626ffadb 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -26,7 +26,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/globebrowsing.scene", + Scene = "${SCENE}/default.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", From 2f6fede0ed33000c8f8c04f4b4bc05f16310dda3 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 7 Apr 2017 11:30:54 -0600 Subject: [PATCH 047/192] build fix --- modules/touch/include/TouchInteraction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 5025df0673..2809bdd3f9 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -95,7 +95,7 @@ class TouchInteraction : public properties::PropertyOwner void step(double dt); void configSensitivities(double dist); void decelerate(); - glm::dvec3 TouchInteraction::modelToScreenSpace(SelectedBody sb); + glm::dvec3 modelToScreenSpace(SelectedBody sb); void clear(); void tap(); From d749d864a1ebd1a5e52b476ae60e6b176d21698f Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 7 Apr 2017 16:30:40 -0600 Subject: [PATCH 048/192] attempted to make zooming velocities smoother --- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 45 +++++++++++++++++------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 2809bdd3f9..15c92113ae 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -95,7 +95,7 @@ class TouchInteraction : public properties::PropertyOwner void step(double dt); void configSensitivities(double dist); void decelerate(); - glm::dvec3 modelToScreenSpace(SelectedBody sb); + glm::dvec2 modelToScreenSpace(SelectedBody sb); void clear(); void tap(); @@ -127,7 +127,6 @@ class TouchInteraction : public properties::PropertyOwner double _projectionScaleFactor; double _currentRadius; std::vector _selected; - std::vector _lastSelected; InteractionType _action; glm::dvec3 _centroid; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 07617d7b5e..cb61cc92a4 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -87,6 +87,20 @@ void TouchInteraction::update(const std::vector& list, std::vector

if(_selected.size() == list.size()) + 1, check if _selected is initialized + 2, define s(xi,q): newXi = T(tx,ty,tz)Q(rx,ry,rz)xi, s(xi,q) = modelToScreenSpace(newXi) + 3, calculate minimum error E = sum( ||s(xi,q)-pi||^2 ) (and define q in the process) + * xi is the old modelview position (_selected.at(i).coordinates), + * q the 6DOF vector (Trans(x,y,z)Quat(x,y,z)) to be defined that will move xi to a new pos, + * pi the current point in screen space (list.at(i).getXY) + 4, Do the inverse rotation of M(q) on the camera, map interactions to different number of direct touch points + + + else + */ interpret(list, lastProcessed); accelerate(list, lastProcessed); } @@ -119,7 +133,7 @@ void TouchInteraction::trace(const std::vector& list) { int id = c.getSessionID(); double dist = length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere; if (dist <= 0.0) { - // finds intersection point between boundingsphere and line in world coordinates, assumes line direction is normalized + // finds intersection closest point between boundingsphere and line in world coordinates, assumes line direction is normalized double d = glm::dot(raytrace, camToSelectable); double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; if (root > 0) // two intersection points (take the closest one) @@ -167,15 +181,9 @@ void TouchInteraction::trace(const std::vector& list) { //debugging for (auto it : newSelected) { std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; - glm::dvec3 screenspace = modelToScreenSpace(it); + //glm::dvec2 screenspace = modelToScreenSpace(it); } - // 1, check if _selected is initialized - // 2, find M(q) that transforms _selected.it->coordinates to newSelected.it->coordinates - // 3, find difference in newSelected and _selected in screen-space - // 4, calculate minimum error - - _lastSelected = _selected; _selected = newSelected; } @@ -266,6 +274,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std }); double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); // make into log space instead + _vel.zoom += zoomFactor * _sensitivity.zoom; } if (_action.pan) { // add local rotation velocity @@ -297,8 +306,15 @@ void TouchInteraction::accelerate(const std::vector& list, const std //std::cout << "x: " << angleX << ", y: " << angleY << "\n"; _vel.localRot = _sensitivity.localRot * glm::dvec2(-angleX, -angleY); } - else { - _vel.zoom = _sensitivity.zoom * (glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere().lengthd()); + else { // should zoom in to current _selected.coordinates position + double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere().lengthd(); + double startDecline = _focusNode->boundingSphere().lengthd() / (0.15 * _projectionScaleFactor); + double factor = 2.0; + if (dist < startDecline) { + factor = 1.0 + std::pow(dist / startDecline, 2); + } + double response = _focusNode->boundingSphere().lengthd() / (factor * _currentRadius * _projectionScaleFactor); + _vel.zoom = _sensitivity.zoom * response; } } @@ -388,10 +404,14 @@ void TouchInteraction::step(double dt) { } -glm::dvec3 TouchInteraction::modelToScreenSpace(SelectedBody sb) { +glm::dvec2 TouchInteraction::modelToScreenSpace(SelectedBody sb) { // returns a dvec2 of -1 to 1 ( top left is (0,0), bottom right is (1,1) ) glm::dvec3 backToScreenSpace = glm::inverse(_camera->rotationQuaternion()) * glm::normalize(((sb.node->rotationMatrix() * sb.coordinates) + sb.node->worldPosition() - _camera->positionVec3())); - return (backToScreenSpace * (-3.2596558 / backToScreenSpace.z)); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + + glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + double aspectRatio = res.x / res.y; + return glm::dvec2(backToScreenSpace.x / (2 * aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); } void TouchInteraction::configSensitivities(double dist) { @@ -437,7 +457,6 @@ void TouchInteraction::clear() { _action.pick = false; _selected.clear(); // should clear if no longer have a direct-touch input - _lastSelected.clear(); } void TouchInteraction::tap() { From 60849e266b2b269d186bdd95ed2682e9721d72ce Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Mon, 10 Apr 2017 21:03:55 -0600 Subject: [PATCH 049/192] small cleanup --- modules/touch/src/TouchInteraction.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index cb61cc92a4..97f2009602 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -79,13 +79,16 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - if (_currentRadius > 0.3) // good value to make any planet sufficiently large for direct-touch - _directTouchMode = true; - else - _directTouchMode = false; - trace(list); + if (_currentRadius > 0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch + _directTouchMode = true; + } + else { + _directTouchMode = false; + } + + /* if (_directTouchMode) @@ -145,9 +148,9 @@ void TouchInteraction::trace(const std::vector& list) { double phi = atan(glm::length(glm::dvec2(pointInModelView.x, pointInModelView.y)) / pointInModelView.z); // Add id, node and surface coordinates to the selected list - auto found = find_if(newSelected.begin(), newSelected.end(), [id](SelectedBody s) { return s.id == id; }); - if (found != newSelected.end()) { - double oldNodeDist = glm::length(found->node->worldPosition() - camPos); + std::vector::iterator oldNode = find_if(newSelected.begin(), newSelected.end(), [id](SelectedBody s) { return s.id == id; }); + if (oldNode != newSelected.end()) { + double oldNodeDist = glm::length(oldNode->node->worldPosition() - camPos); if (glm::length(camToSelectable) < oldNodeDist) { // new node is closer, remove added node and add the new one instead newSelected.pop_back(); newSelected.push_back({ id, node, pointInModelView }); From 53f679ae921426d9f8e8588679a16fb974170e0b Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 11 Apr 2017 15:15:13 -0600 Subject: [PATCH 050/192] crash fix, _camera and _focusNode now have to be declared outside the constructor --- modules/touch/include/TouchInteraction.h | 3 ++- modules/touch/src/TouchInteraction.cpp | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 15c92113ae..ee7062f143 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -34,7 +34,7 @@ #include #include #include - +#include #include #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED @@ -120,6 +120,7 @@ class TouchInteraction : public properties::PropertyOwner Camera* _camera; SceneGraphNode* _focusNode = nullptr; properties::StringProperty _origin; + properties::Vec2Property _touchScreenSize; globebrowsing::RenderableGlobe* _globe; bool _tap; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 97f2009602..1560a09a6f 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -55,16 +55,17 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), - _origin("origin", "Origin", ""), - _camera{ OsEng.interactionHandler().camera() }, + _origin("origin", "Origin", ""), _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, + _touchScreenSize("normalizer", "Touch Screen Normalizer", glm::vec2(122, 68), glm::vec2(0), glm::vec2(1000)), // glm::vec2(width, height) in cm. (13.81, 6.7) for iphone 6s plus _centroid{ glm::dvec3(0.0) }, _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _directTouchMode{ false }, _tap{ false } { + addProperty(_touchScreenSize); _origin.onChange([this]() { SceneGraphNode* node = sceneGraphNode(_origin.value()); if (!node) { @@ -73,14 +74,15 @@ TouchInteraction::TouchInteraction() } setFocusNode(node); }); - } TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - trace(list); + setCamera(OsEng.interactionHandler().camera()); + setFocusNode(OsEng.interactionHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode) + trace(list); if (_currentRadius > 0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch _directTouchMode = true; } @@ -326,8 +328,9 @@ void TouchInteraction::accelerate(const std::vector& list, const std void TouchInteraction::step(double dt) { using namespace glm; - setFocusNode(OsEng.interactionHandler().focusNode()); // since setFocusNode cant be called directly (TouchInteraction not a subclass of InteractionMode) - if (_focusNode) { + setCamera(OsEng.interactionHandler().camera()); + setFocusNode(OsEng.interactionHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode) + if (_focusNode && _camera) { // Create variables from current state dvec3 camPos = _camera->positionVec3(); dvec3 centerPos = _focusNode->worldPosition(); From ab877feaf989de3201f31e090deea4ad803930be Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 12 Apr 2017 14:37:28 -0600 Subject: [PATCH 051/192] first step for LM algorithm on screen-space points, camera/focusnode causes crashes if not initialized, where do we do this best? --- modules/touch/CMakeLists.txt | 2 + modules/touch/ext/levmarq.cpp | 221 +++++++++++++++++++++++ modules/touch/ext/levmarq.h | 51 ++++++ modules/touch/include/TouchInteraction.h | 2 + modules/touch/src/TouchInteraction.cpp | 83 ++++++--- modules/touch/touchmodule.cpp | 3 + 6 files changed, 336 insertions(+), 26 deletions(-) create mode 100644 modules/touch/ext/levmarq.cpp create mode 100644 modules/touch/ext/levmarq.h diff --git a/modules/touch/CMakeLists.txt b/modules/touch/CMakeLists.txt index 0951da2c6b..48f12b0afb 100644 --- a/modules/touch/CMakeLists.txt +++ b/modules/touch/CMakeLists.txt @@ -25,12 +25,14 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.h ${CMAKE_CURRENT_SOURCE_DIR}/include/TuioEar.h ${CMAKE_CURRENT_SOURCE_DIR}/include/TouchInteraction.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TuioEar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TouchInteraction.cpp ) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp new file mode 100644 index 0000000000..349ffe99a4 --- /dev/null +++ b/modules/touch/ext/levmarq.cpp @@ -0,0 +1,221 @@ +/* +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files(the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions : + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#define TOL 1e-30 // smallest value allowed in cholesky_decomp() + + +// set parameters required by levmarq() to default values +void levmarq_init(LMstat *lmstat) { + lmstat->verbose = 0; + lmstat->max_it = 10000; + lmstat->init_lambda = 0.0001; + lmstat->up_factor = 10; + lmstat->down_factor = 10; + lmstat->target_derr = 1e-12; +} + + +/* +perform least-squares minimization using the Levenberg-Marquardt algorithm. +The arguments are as follows: + npar number of parameters + par array of parameters to be varied + ny number of measurements to be fit + y array of measurements + dysq array of error in measurements, squared + (set dysq=NULL for unweighted least-squares) + func function to be fit + grad gradient of "func" with respect to the input parameters + fdata pointer to any additional data required by the function + lmstat pointer to the "status" structure, where minimization parameters + are set and the final status is returned. + +Before calling levmarq, several of the parameters in lmstat must be set. +For default values, call levmarq_init(lmstat). +*/ +int levmarq(int npar, double *par, int ny, double *y, double *dysq, + double (*func)(double *, int, void *), + void (*grad)(double *, double *, int, void *), + void *fdata, LMstat *lmstat) { + + int x, i, j, it, nit, ill, verbose; + double lambda, up, down, mult, weight, err, newerr, derr, target_derr; + + // allocate the arrays + double** h = new double*[npar]; + double** ch = new double*[npar]; + for (int i = 0; i < npar; i++) { + h[i] = new double[npar]; + ch[i] = new double[npar]; + } + double* g = new double[npar]; + double* d = new double[npar]; + double* delta = new double[npar]; + double* newpar = new double[npar]; + + verbose = lmstat->verbose; + nit = lmstat->max_it; + lambda = lmstat->init_lambda; + up = lmstat->up_factor; + down = 1/lmstat->down_factor; + target_derr = lmstat->target_derr; + weight = 1; + derr = newerr = 0; // to avoid compiler warnings + + // calculate the initial error ("chi-squared") + err = error_func(par, ny, y, dysq, func, fdata); + + // main iteration + for (it = 0; it < nit; it++) { + // calculate the approximation to the Hessian and the "derivative" d + for (i = 0; i < npar; i++) { + d[i] = 0; + for (j = 0; j <= i; j++) + h[i][j] = 0; + } + for (x = 0; x < ny; x++) { + if (dysq) + weight = 1/dysq[x]; // for weighted least-squares + grad(g, par, x, fdata); + for (i = 0; i < npar; i++) { + d[i] += (y[x] - func(par, x, fdata)) * g[i] * weight; + for (j = 0; j <= i; j++) + h[i][j] += g[i] * g[j] * weight; + } + } + // make a step "delta." If the step is rejected, increase lambda and try again + mult = 1 + lambda; + ill = 1; // ill-conditioned? + while (ill && (it 0); + } + if (verbose) + printf("it = %4d, lambda = %10g, err = %10g, derr = %10g\n", it, lambda, err, derr); + if (ill) { + mult = (1 + lambda * up) / (1 + lambda); + lambda *= up; + it++; + } + } + for (i = 0; i < npar; i++) + par[i] = newpar[i]; + err = newerr; + lambda *= down; + + if ((!ill) && (-derrfinal_it = it; + lmstat->final_err = err; + lmstat->final_derr = derr; + + // deallocate the arrays + for (int i = 0; i < npar; i++) { + delete[] h[i]; + delete[] ch[i]; + } + delete[] h; + delete[] ch; + delete[] g; + delete[] d; + delete[] delta; + delete[] newpar; + + return (it==nit); +} + + +// calculate the error function (chi-squared) +double error_func(double *par, int ny, double *y, double *dysq, + double (*func)(double *, int, void *), void *fdata) { + int x; + double res,e=0; + + for (x=0; x= 0; i--) { + sum = 0; + for (j = i+1; j < n; j++) + sum += l[j][i] * x[j]; + x[i] = (x[i] - sum) / l[i][i]; + } +} + + + +// symmetric, positive-definite matrix "a" and returns its (lower-triangular) Cholesky factor in "l", if l=a the decomposition is performed in place, elements above the diagonal are ignored. +int cholesky_decomp(int n, double** l, double** a) { + int i,j,k; + double sum; + for (i = 0; i < n; i++) { + for (j = 0; j < i; j++) { + sum = 0; + for (k = 0; k < j; k++) + sum += l[i][k] * l[j][k]; + l[i][j] = (a[i][j] - sum) / l[j][j]; + } + sum = 0; + for (k = 0; k < i; k++) + sum += l[i][k] * l[i][k]; + sum = a[i][i] - sum; + if (sum < TOL) + return 1; // not positive-definite + l[i][i] = sqrt(sum); + } + return 0; +} diff --git a/modules/touch/ext/levmarq.h b/modules/touch/ext/levmarq.h new file mode 100644 index 0000000000..3b5117edd7 --- /dev/null +++ b/modules/touch/ext/levmarq.h @@ -0,0 +1,51 @@ +/* +levmarq.c and levmarq.h are provided under the MIT license. +Copyright(c) 2008 - 2016 Ron Babich + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files(the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions : + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +*/ + +typedef struct { + int verbose; + int max_it; + double init_lambda; + double up_factor; + double down_factor; + double target_derr; + int final_it; + double final_err; + double final_derr; +} LMstat; + +void levmarq_init(LMstat *lmstat); + +int levmarq(int npar, double *par, int ny, double *y, double *dysq, + double (*func)(double *, int, void *), + void (*grad)(double *, double *, int, void *), + void *fdata, LMstat *lmstat); + +double error_func(double *par, int ny, double *y, double *dysq, + double (*func)(double *, int, void *), void *fdata); + +void solve_axb_cholesky(int n, double** l, double* x, double* b); + +int cholesky_decomp(int n, double** l, double** a); diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index ee7062f143..f7673ebf2a 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -130,6 +131,7 @@ class TouchInteraction : public properties::PropertyOwner std::vector _selected; InteractionType _action; + LMstat _lmstat; glm::dvec3 _centroid; VelocityStates _vel; ScaleFactor _friction; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 1560a09a6f..bc44d1bd93 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -59,13 +59,15 @@ TouchInteraction::TouchInteraction() _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, - _touchScreenSize("normalizer", "Touch Screen Normalizer", glm::vec2(122, 68), glm::vec2(0), glm::vec2(1000)), // glm::vec2(width, height) in cm. (13.81, 6.7) for iphone 6s plus + _touchScreenSize("TouchScreenSize", "Touch Screen Normalizer", glm::vec2(122, 68), glm::vec2(0), glm::vec2(1000)), // glm::vec2(width, height) in cm. (13.81, 6.7) for iphone 6s plus _centroid{ glm::dvec3(0.0) }, _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. + _currentRadius{ 1.0 }, _directTouchMode{ false }, _tap{ false } { addProperty(_touchScreenSize); + levmarq_init(&_lmstat); _origin.onChange([this]() { SceneGraphNode* node = sceneGraphNode(_origin.value()); if (!node) { @@ -79,35 +81,64 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - setCamera(OsEng.interactionHandler().camera()); - setFocusNode(OsEng.interactionHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode) - trace(list); - if (_currentRadius > 0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch + if (/*_currentRadius > 0.3 &&*/ _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition _directTouchMode = true; } else { _directTouchMode = false; } + + if (_directTouchMode) { + /* + 1, define s(xi,q): newXi = T(tx,ty,tz)Q(rx,ry,rz)xi, s(xi,q) = modelToScreenSpace(newXi) + 2, calculate minimum error E = sum( ||s(xi,q)-pi||^2 ) (and define q in the process) + * xi is the old modelview position (_selected.at(i).coordinates), + * q the 6DOF vector (Trans(x,y,z)Quat(x,y,z)) to be defined that will move xi to a new pos, + * pi the current point in screen space (list.at(i).getXY) + 3, Do the inverse rotation of M(q) on the camera, map interactions to different number of direct touch points + */ + // define these according to the M(q) + auto func = [](double* par, int x, void* fdata) { + return par[0] + (par[1] - par[0]) * exp(-par[2] * x); + }; + auto grad = [](double* g, double* par, int x, void* fdata) { + g[0] = 1.0 + exp(-par[2] * x); + g[1] = exp(-par[2] * x); + g[2] = -x * (par[1] - par[0]) * exp(-par[2] * x); + }; + + + + const int nDOF = 6; // 6 degrees of freedom + //glm::dquat quat = glm::quat_cast(_selected.at(0).node->rotationMatrix()); + //glm::dvec3 trans = _sekected.at(0).node->worldPosition(); + double q[nDOF] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // initial values of q or 0.0? (ie current model or no rotation/translation) + const int nFingers = _selected.size() * 2; + double* contactPoints = new double[nFingers]; + double* squaredError = new double[nFingers]; + int i = 0; + for (const SelectedBody& sb : _selected) { + glm::dvec2 screenPoint = modelToScreenSpace(sb); // transform to screen-space + contactPoints[i] = screenPoint.x; + contactPoints[i + 1] = screenPoint.y; + + std::vector::const_iterator cursor = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return sb.id == c.getSessionID(); }); + squaredError[i] = pow(screenPoint.x - cursor->getX(), 2); // squared error to calculate weighted least-square + squaredError[i + 1] = pow(screenPoint.y - cursor->getY(), 2); + + i += 2; + } + levmarq_init(&_lmstat); + int nIterations = levmarq(nDOF, q, nFingers, contactPoints, squaredError, func, grad, NULL, &_lmstat); + delete[] contactPoints; + delete[] squaredError; + } + //else { + interpret(list, lastProcessed); + accelerate(list, lastProcessed); + //} - - - /* - if (_directTouchMode) - assumes all contact points are direct --> if(_selected.size() == list.size()) - 1, check if _selected is initialized - 2, define s(xi,q): newXi = T(tx,ty,tz)Q(rx,ry,rz)xi, s(xi,q) = modelToScreenSpace(newXi) - 3, calculate minimum error E = sum( ||s(xi,q)-pi||^2 ) (and define q in the process) - * xi is the old modelview position (_selected.at(i).coordinates), - * q the 6DOF vector (Trans(x,y,z)Quat(x,y,z)) to be defined that will move xi to a new pos, - * pi the current point in screen space (list.at(i).getXY) - 4, Do the inverse rotation of M(q) on the camera, map interactions to different number of direct touch points - - - else - */ - interpret(list, lastProcessed); - accelerate(list, lastProcessed); } void TouchInteraction::trace(const std::vector& list) { @@ -132,10 +163,10 @@ void TouchInteraction::trace(const std::vector& list) { double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -3.2596558); glm::dvec3 raytrace = glm::normalize(cursorInWorldSpace); + int id = c.getSessionID(); for (SceneGraphNode* node : selectableNodes) { double boundingSphere = node->boundingSphere().lengthd(); glm::dvec3 camToSelectable = node->worldPosition() - camPos; - int id = c.getSessionID(); double dist = length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere; if (dist <= 0.0) { // finds intersection closest point between boundingsphere and line in world coordinates, assumes line direction is normalized @@ -302,6 +333,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std _vel.localRoll += -rollFactor * _sensitivity.localRoll; } if (_action.pick) { // pick something in the scene as focus node + if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { _focusNode = _selected.at(0).node; // rotate camera to look at new focus OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode @@ -328,7 +360,6 @@ void TouchInteraction::accelerate(const std::vector& list, const std void TouchInteraction::step(double dt) { using namespace glm; - setCamera(OsEng.interactionHandler().camera()); setFocusNode(OsEng.interactionHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode) if (_focusNode && _camera) { // Create variables from current state @@ -355,7 +386,7 @@ void TouchInteraction::step(double dt) { double distance = std::max(length(centerToCamera) - boundingSphere, 0.0); _currentRadius = boundingSphere / std::max(distance * _projectionScaleFactor, 1.0); - + { // Roll dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); localCamRot = localCamRot * camRollRot; diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 22a3b1e96a..0a6bbba6de 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -123,6 +123,9 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::PreSync, [&]() { + touch->setCamera(OsEng.interactionHandler().camera()); + touch->setFocusNode(OsEng.interactionHandler().focusNode()); + if (gotNewInput() && OsEng.windowWrapper().isMaster()) { touch->update(list, lastProcessed); From f2aebcd880e12653684024010f610a08ec326323 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 12 Apr 2017 16:54:13 -0600 Subject: [PATCH 052/192] one step closer, need to figure out gradient of func and how to send cam/node/aspectratio with void* fdata --- modules/touch/ext/levmarq.cpp | 4 +-- modules/touch/src/TouchInteraction.cpp | 44 ++++++++++++++++++-------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 349ffe99a4..7b0ff125ad 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -163,9 +163,9 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, double error_func(double *par, int ny, double *y, double *dysq, double (*func)(double *, int, void *), void *fdata) { int x; - double res,e=0; + double res, e = 0; - for (x=0; x& list, std::vector& lastProcessed) { - trace(list); - if (/*_currentRadius > 0.3 &&*/ _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition - _directTouchMode = true; - } - else { - _directTouchMode = false; - } - - if (_directTouchMode) { + if (_directTouchMode) { // should just be a function call /* 1, define s(xi,q): newXi = T(tx,ty,tz)Q(rx,ry,rz)xi, s(xi,q) = modelToScreenSpace(newXi) 2, calculate minimum error E = sum( ||s(xi,q)-pi||^2 ) (and define q in the process) @@ -99,8 +91,27 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

& list, std::vector

0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition + _directTouchMode = true; + } + else { + _directTouchMode = false; + } } void TouchInteraction::trace(const std::vector& list) { From a614f1ffda967aa088e5820d764ead0f12e5180a Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Thu, 13 Apr 2017 21:27:38 +0200 Subject: [PATCH 053/192] Remove some power scaled coordinates. Remove spice dependency from sphere geometry. Remove dead code. Clean up bounding sphere code. --- .../scene/atmosphereearth/atmosphereearth.mod | 12 +-- data/scene/earth/earth.mod | 4 +- data/scene/jupiter/callisto/callisto.mod | 2 +- data/scene/jupiter/europa/europa.mod | 2 +- data/scene/jupiter/ganymede/ganymede.mod | 2 +- data/scene/jupiter/io/io.mod | 2 +- data/scene/jupiter/jupiter/jupiter.mod | 2 +- data/scene/mars/mars.mod | 2 +- data/scene/mercury/mercury.mod | 4 +- data/scene/missions/dawn/ceres/ceres.mod | 2 +- .../newhorizons/jupiter/callisto/callisto.mod | 4 +- .../newhorizons/jupiter/europa/europa.mod | 4 +- .../newhorizons/jupiter/ganymede/ganymede.mod | 4 +- .../missions/newhorizons/jupiter/io/io.mod | 2 +- .../newhorizons/jupiter/jupiter/jupiter.mod | 4 +- .../newhorizons/pluto/charon/charon.mod | 4 +- .../newhorizons/pluto/hydra/hydra.mod | 2 +- .../newhorizons/pluto/kerberos/kerberos.mod | 2 +- .../missions/newhorizons/pluto/nix/nix.mod | 4 +- .../newhorizons/pluto/pluto/pluto.mod | 6 +- .../missions/newhorizons/pluto/styx/styx.mod | 4 +- data/scene/moon/moon.mod | 6 +- data/scene/neptune/neptune.mod | 2 +- data/scene/pluto/pluto.mod | 4 +- data/scene/saturn/dione/dione.mod | 2 +- data/scene/saturn/enceladus/enceladus.mod | 2 +- data/scene/saturn/iapetus/iapetus.mod | 2 +- data/scene/saturn/mimas/mimas.mod | 2 +- data/scene/saturn/rhea/rhea.mod | 2 +- data/scene/saturn/saturn/saturn.mod | 5 +- data/scene/saturn/tethys/tethys.mod | 2 +- data/scene/saturn/titan/titan.mod | 2 +- data/scene/sun/sun.mod | 7 +- data/scene/uranus/uranus.mod | 2 +- data/scene/venus/venus.mod | 2 +- include/openspace/rendering/renderable.h | 7 +- include/openspace/scene/scene.h | 5 -- include/openspace/scene/scenegraphnode.h | 8 +- include/openspace/util/powerscaledsphere.h | 4 +- modules/base/rendering/modelgeometry.cpp | 2 +- modules/base/rendering/renderableplane.cpp | 23 +++-- modules/base/rendering/renderableplane.h | 3 +- .../rendering/renderablesphericalgrid.cpp | 9 +- .../base/rendering/renderablesphericalgrid.h | 1 - .../rendering/renderabledebugplane.cpp | 24 +++--- .../rendering/renderabledebugplane.h | 3 +- .../globebrowsing/globes/renderableglobe.cpp | 2 +- .../globebrowsing/other/distanceswitch.cpp | 4 +- .../rendering/renderablemodelprojection.cpp | 6 +- .../rendering/renderableplaneprojection.cpp | 13 --- .../rendering/renderableplaneprojection.h | 1 - .../rendering/renderableplanetprojection.cpp | 4 +- modules/space/rendering/renderableplanet.cpp | 44 +++++++--- modules/space/rendering/renderablerings.cpp | 2 +- .../space/rendering/simplespheregeometry.cpp | 70 +++++++-------- .../space/rendering/simplespheregeometry.h | 11 +-- src/interaction/interactionmode.cpp | 2 +- src/rendering/renderable.cpp | 8 +- src/rendering/renderengine.cpp | 2 - src/scene/scene.cpp | 13 --- src/scene/scenegraphnode.cpp | 86 ++----------------- src/util/powerscaledsphere.cpp | 48 ++--------- 62 files changed, 178 insertions(+), 343 deletions(-) diff --git a/data/scene/atmosphereearth/atmosphereearth.mod b/data/scene/atmosphereearth/atmosphereearth.mod index f5c98aaf3f..b019c71241 100644 --- a/data/scene/atmosphereearth/atmosphereearth.mod +++ b/data/scene/atmosphereearth/atmosphereearth.mod @@ -30,15 +30,15 @@ return { Source1 = { Name = "Sun", -- All radius in meters - Radius = {696.3, 6} + Radius = 696.3E6 }, - --Source2 = { Name = "Monolith", Radius = {0.01, 6} }, + --Source2 = { Name = "Monolith", Radius = 0.01E6 }, Caster1 = { Name = "Moon", -- All radius in meters - Radius = {1.737, 6} + Radius = 1.737E6 }, - --Caster2 = { Name = "Independency Day Ship", Radius = {0.0, 0.0} } + --Caster2 = { Name = "Independency Day Ship", Radius = 0 } }, Textures = { Type = "simple", @@ -127,7 +127,7 @@ return { Parent = "Earth", Renderable = { Type = "RenderablePlane", - Size = {3.0, 11.0}, + Size = 3.0E11.0, Origin = "Center", Billboard = true, Texture = "textures/marker.png", @@ -145,7 +145,7 @@ return { -- Renderable = { -- Type = "RenderablePlane", -- Billboard = true, - -- Size = { 6.371, 6 }, + -- Size = 6.371E6, -- Texture = "textures/graph.jpg", -- Atmosphere = { -- Type = "Nishita", -- for example, values missing etc etc diff --git a/data/scene/earth/earth.mod b/data/scene/earth/earth.mod index 78b3a3bb90..8ea0411ba9 100644 --- a/data/scene/earth/earth.mod +++ b/data/scene/earth/earth.mod @@ -34,7 +34,7 @@ return { Body = "EARTH", Geometry = { Type = "SimpleSphere", - Radius = { 6.371, 6 }, + Radius = 6.371E6, Segments = 100 }, Textures = { @@ -88,7 +88,7 @@ return { Parent = "Earth", Renderable = { Type = "RenderablePlane", - Size = {3.0, 11.0}, + Size = 3.0E11, Origin = "Center", Billboard = true, Texture = "textures/marker.png", diff --git a/data/scene/jupiter/callisto/callisto.mod b/data/scene/jupiter/callisto/callisto.mod index 74c3360adf..aa6122bd47 100644 --- a/data/scene/jupiter/callisto/callisto.mod +++ b/data/scene/jupiter/callisto/callisto.mod @@ -9,7 +9,7 @@ return { Body = "CALLISTO", Geometry = { Type = "SimpleSphere", - Radius = { 2.631, 6}, + Radius = 2.631E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/europa/europa.mod b/data/scene/jupiter/europa/europa.mod index 54df372720..fea16b4627 100644 --- a/data/scene/jupiter/europa/europa.mod +++ b/data/scene/jupiter/europa/europa.mod @@ -9,7 +9,7 @@ return { Body = "EUROPA", Geometry = { Type = "SimpleSphere", - Radius = { 1.561, 6}, + Radius = 1.561E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/ganymede/ganymede.mod b/data/scene/jupiter/ganymede/ganymede.mod index c2c9fdca08..16aa1c175a 100644 --- a/data/scene/jupiter/ganymede/ganymede.mod +++ b/data/scene/jupiter/ganymede/ganymede.mod @@ -9,7 +9,7 @@ return { Body = "JUPITER BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 2.631, 6}, + Radius = 2.631E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/io/io.mod b/data/scene/jupiter/io/io.mod index 03d28e60d1..98e5e88e7f 100644 --- a/data/scene/jupiter/io/io.mod +++ b/data/scene/jupiter/io/io.mod @@ -9,7 +9,7 @@ return { Body = "IO", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { diff --git a/data/scene/jupiter/jupiter/jupiter.mod b/data/scene/jupiter/jupiter/jupiter.mod index 6302b66739..ef3e05a17c 100644 --- a/data/scene/jupiter/jupiter/jupiter.mod +++ b/data/scene/jupiter/jupiter/jupiter.mod @@ -22,7 +22,7 @@ return { Body = "JUPITER BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 0.71492, 8 }, + Radius = 0.71492E8, Segments = 200 }, Textures = { diff --git a/data/scene/mars/mars.mod b/data/scene/mars/mars.mod index 54e33cbd6c..6fffe637bd 100644 --- a/data/scene/mars/mars.mod +++ b/data/scene/mars/mars.mod @@ -22,7 +22,7 @@ return { Body = "MARS BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 6.390, 6 }, + Radius = 6.390E6, Segments = 100 }, Textures = { diff --git a/data/scene/mercury/mercury.mod b/data/scene/mercury/mercury.mod index aa4be9675d..7fbd818df0 100644 --- a/data/scene/mercury/mercury.mod +++ b/data/scene/mercury/mercury.mod @@ -1,5 +1,3 @@ -MercuryRadius = 2.4397E6; - return { -- Mercury barycenter module { @@ -24,7 +22,7 @@ return { Body = "MERCURY", Geometry = { Type = "SimpleSphere", - Radius = {MercuryRadius, 1.0}, + Radius = 2.4397E6, Segments = 100 }, Textures = { diff --git a/data/scene/missions/dawn/ceres/ceres.mod b/data/scene/missions/dawn/ceres/ceres.mod index ff9c413a2a..0c29ae852b 100644 --- a/data/scene/missions/dawn/ceres/ceres.mod +++ b/data/scene/missions/dawn/ceres/ceres.mod @@ -10,7 +10,7 @@ return { Body = "CERES", Geometry = { Type = "SimpleSphere", - Radius = { 6.390, 5 }, + Radius = 6.390E5, Segments = 100 }, Textures = { diff --git a/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod b/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod index acf03fd873..8ebe7a4081 100644 --- a/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod +++ b/data/scene/missions/newhorizons/jupiter/callisto/callisto.mod @@ -9,7 +9,7 @@ return { Body = "CALLISTO", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { @@ -58,7 +58,7 @@ return { Parent = "Callisto", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.4}, + Size = 1.0E7.4, Origin = "Center", Billboard = true, Texture = "textures/Callisto-Text.png", diff --git a/data/scene/missions/newhorizons/jupiter/europa/europa.mod b/data/scene/missions/newhorizons/jupiter/europa/europa.mod index 1bec7e5c9b..5f806496e9 100644 --- a/data/scene/missions/newhorizons/jupiter/europa/europa.mod +++ b/data/scene/missions/newhorizons/jupiter/europa/europa.mod @@ -9,7 +9,7 @@ return { Body = "EUROPA", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { @@ -58,7 +58,7 @@ return { Parent = "Europa", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.4}, + Size = 1.0E7.4, Origin = "Center", Billboard = true, Texture = "textures/Europa-Text.png", diff --git a/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod b/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod index 401babcca6..a7881254eb 100644 --- a/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod +++ b/data/scene/missions/newhorizons/jupiter/ganymede/ganymede.mod @@ -9,7 +9,7 @@ return { Body = "GANYMEDE", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { @@ -58,7 +58,7 @@ return { Parent = "Ganymede", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.4}, + Size = 1.0E7.4, Origin = "Center", Billboard = true, Texture = "textures/Ganymede-Text.png", diff --git a/data/scene/missions/newhorizons/jupiter/io/io.mod b/data/scene/missions/newhorizons/jupiter/io/io.mod index c41b45f29b..d4e5260cbd 100644 --- a/data/scene/missions/newhorizons/jupiter/io/io.mod +++ b/data/scene/missions/newhorizons/jupiter/io/io.mod @@ -9,7 +9,7 @@ return { Body = "IO", Geometry = { Type = "SimpleSphere", - Radius = { 1.8213, 6 }, + Radius = 1.8213E6, Segments = 100 }, Textures = { diff --git a/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod b/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod index 079357b2ad..82762acf21 100644 --- a/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod +++ b/data/scene/missions/newhorizons/jupiter/jupiter/jupiter.mod @@ -22,7 +22,7 @@ return { Body = "JUPITER", Geometry = { Type = "SimpleSphere", - Radius = { 0.71492, 8 }, + Radius = 0.71492E8, Segments = 200, }, Textures = { @@ -101,7 +101,7 @@ return { Parent = "JupiterProjection", Renderable = { Type = "RenderablePlane", - Size = {1.0, 7.5}, + Size = 1.0E7.5, Origin = "Center", Billboard = true, Texture = "textures/Jupiter-text.png", diff --git a/data/scene/missions/newhorizons/pluto/charon/charon.mod b/data/scene/missions/newhorizons/pluto/charon/charon.mod index 4cfff1d131..2d50c40e44 100644 --- a/data/scene/missions/newhorizons/pluto/charon/charon.mod +++ b/data/scene/missions/newhorizons/pluto/charon/charon.mod @@ -24,7 +24,7 @@ return { Type = "RenderablePlanetProjection", Geometry = { Type = "SimpleSphere", - Radius = { 6.035 , 5 }, + Radius = 6.035E5, Segments = 100 }, Textures = { @@ -72,7 +72,7 @@ return { Parent = "Charon", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 1.0E6.3, Origin = "Center", Billboard = true, Texture = "textures/Charon-Text.png", diff --git a/data/scene/missions/newhorizons/pluto/hydra/hydra.mod b/data/scene/missions/newhorizons/pluto/hydra/hydra.mod index 8dcf6d2d0f..09950fc602 100644 --- a/data/scene/missions/newhorizons/pluto/hydra/hydra.mod +++ b/data/scene/missions/newhorizons/pluto/hydra/hydra.mod @@ -46,7 +46,7 @@ return { Parent = "Hydra", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 1.0E6.3, Origin = "Center", Billboard = true, Texture = "textures/Hydra-Text.png" diff --git a/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod b/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod index 595baf13e8..e415ce3cbd 100644 --- a/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod +++ b/data/scene/missions/newhorizons/pluto/kerberos/kerberos.mod @@ -46,7 +46,7 @@ return { Parent = "Kerberos", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 1.0E6.3, Origin = "Center", Billboard = true, Texture = "textures/Kerberos-Text.png" diff --git a/data/scene/missions/newhorizons/pluto/nix/nix.mod b/data/scene/missions/newhorizons/pluto/nix/nix.mod index da05401b4e..1ef3484e3b 100644 --- a/data/scene/missions/newhorizons/pluto/nix/nix.mod +++ b/data/scene/missions/newhorizons/pluto/nix/nix.mod @@ -19,7 +19,7 @@ return { Body = "NIX", Geometry = { Type = "SimpleSphere", - Radius = { 0.45 , 5 }, + Radius = 0.45E5, Segments = 100 }, Textures = { @@ -46,7 +46,7 @@ return { Parent = "Nix", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 1.0E6.3, Origin = "Center", Billboard = true, Texture = "textures/Nix-Text.png" diff --git a/data/scene/missions/newhorizons/pluto/pluto/pluto.mod b/data/scene/missions/newhorizons/pluto/pluto/pluto.mod index 53118f9e84..53f1773f3e 100644 --- a/data/scene/missions/newhorizons/pluto/pluto/pluto.mod +++ b/data/scene/missions/newhorizons/pluto/pluto/pluto.mod @@ -38,7 +38,7 @@ return { Type = "RenderablePlanetProjection", Geometry = { Type = "SimpleSphere", - Radius = { 1.173 , 6 }, + Radius = 1.173E6, Segments = 100 }, Textures = { @@ -173,7 +173,7 @@ return { Renderable = { Type = "RenderablePlane", Billboard = true, - Size = { 5, 4 }, + Size = 5E4, Texture = "textures/barycenter.png", Atmosphere = { Type = "Nishita", -- for example, values missing etc etc @@ -187,7 +187,7 @@ return { Parent = "Pluto", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 1.0E6.3, Origin = "Center", Billboard = true, Texture = "textures/Pluto-Text.png", diff --git a/data/scene/missions/newhorizons/pluto/styx/styx.mod b/data/scene/missions/newhorizons/pluto/styx/styx.mod index 559062be97..ab914cddb9 100644 --- a/data/scene/missions/newhorizons/pluto/styx/styx.mod +++ b/data/scene/missions/newhorizons/pluto/styx/styx.mod @@ -19,7 +19,7 @@ return { Body = "STYX", Geometry = { Type = "SimpleSphere", - Radius = { 0.75 , 4 }, + Radius = 0.75E4, Segments = 100 }, Textures = { @@ -46,7 +46,7 @@ return { Parent = "Styx", Renderable = { Type = "RenderablePlane", - Size = {1.0, 6.3}, + Size = 1.0E6.3, Origin = "Center", Billboard = true, Texture = "textures/Styx-Text.png", diff --git a/data/scene/moon/moon.mod b/data/scene/moon/moon.mod index b58b056dcb..534adf617c 100644 --- a/data/scene/moon/moon.mod +++ b/data/scene/moon/moon.mod @@ -9,17 +9,17 @@ return { Body = "MOON", Geometry = { Type = "SimpleSphere", - Radius = { 1.737, 6}, + Radius = 1.737E6, Segments = 100 }, Shadow_Group = { Source1 = { Name = "Sun", - Radius = {696.3, 6} + Radius = 696.3E6 }, Caster1 = { Name = "Earth", - Radius = {6.371, 6} + Radius = 6.371E6 }, }, Textures = { diff --git a/data/scene/neptune/neptune.mod b/data/scene/neptune/neptune.mod index 5967f0a8fe..fbad419c08 100644 --- a/data/scene/neptune/neptune.mod +++ b/data/scene/neptune/neptune.mod @@ -23,7 +23,7 @@ return { Body = "NEPTUNE BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 2.4622 , 7 }, + Radius = 2.4622E7, Segments = 100 }, Textures = { diff --git a/data/scene/pluto/pluto.mod b/data/scene/pluto/pluto.mod index 88346771ef..27f540d731 100644 --- a/data/scene/pluto/pluto.mod +++ b/data/scene/pluto/pluto.mod @@ -25,7 +25,7 @@ return { Body = "PLUTO", Geometry = { Type = "SimpleSphere", - Radius = { 1.173 , 6 }, + Radius = 1.173E6, Segments = 100 }, Textures = { @@ -61,7 +61,7 @@ return { Body = "CHARON", Geometry = { Type = "SimpleSphere", - Radius = { 6.035 , 5 }, + Radius = 6.035E5, Segments = 100 }, Textures = { diff --git a/data/scene/saturn/dione/dione.mod b/data/scene/saturn/dione/dione.mod index d132bea897..477705ea2b 100644 --- a/data/scene/saturn/dione/dione.mod +++ b/data/scene/saturn/dione/dione.mod @@ -8,7 +8,7 @@ return { Body = "DIONE", Geometry = { Type = "SimpleSphere", - Radius = { 0.563, 3 }, + Radius = 0.563E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/enceladus/enceladus.mod b/data/scene/saturn/enceladus/enceladus.mod index 1d3011e4c8..f49104d3ca 100644 --- a/data/scene/saturn/enceladus/enceladus.mod +++ b/data/scene/saturn/enceladus/enceladus.mod @@ -8,7 +8,7 @@ return { Body = "ENCELADUS", Geometry = { Type = "SimpleSphere", - Radius = { 0.257, 3 }, + Radius = 0.257E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/iapetus/iapetus.mod b/data/scene/saturn/iapetus/iapetus.mod index a390af3ec4..0bcc6b8c38 100644 --- a/data/scene/saturn/iapetus/iapetus.mod +++ b/data/scene/saturn/iapetus/iapetus.mod @@ -8,7 +8,7 @@ return { Body = "IAPETUS", Geometry = { Type = "SimpleSphere", - Radius = { 0.746, 3 }, + Radius = 0.746E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/mimas/mimas.mod b/data/scene/saturn/mimas/mimas.mod index bf7b451d83..9f8e5242e6 100644 --- a/data/scene/saturn/mimas/mimas.mod +++ b/data/scene/saturn/mimas/mimas.mod @@ -8,7 +8,7 @@ return { Body = "MIMAS", Geometry = { Type = "SimpleSphere", - Radius = { 0.28, 3 }, + Radius = 0.28E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/rhea/rhea.mod b/data/scene/saturn/rhea/rhea.mod index 623dd479a6..8bb6c61393 100644 --- a/data/scene/saturn/rhea/rhea.mod +++ b/data/scene/saturn/rhea/rhea.mod @@ -8,7 +8,7 @@ return { Body = "RHEA", Geometry = { Type = "SimpleSphere", - Radius = { 0.765, 3 }, + Radius = 0.765E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/saturn/saturn.mod b/data/scene/saturn/saturn/saturn.mod index 4dc0a215c6..c5262ce52f 100644 --- a/data/scene/saturn/saturn/saturn.mod +++ b/data/scene/saturn/saturn/saturn.mod @@ -1,6 +1,3 @@ -SaturnRadius = 5.8232E7; - - return { -- Saturn barycenter module { @@ -26,7 +23,7 @@ return { Body = "SATURN BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = {SaturnRadius, 0}, + Radius = 5.8232E7, Segments = 100 }, Textures = { diff --git a/data/scene/saturn/tethys/tethys.mod b/data/scene/saturn/tethys/tethys.mod index eb2a84b3f9..8fe16fa3cd 100644 --- a/data/scene/saturn/tethys/tethys.mod +++ b/data/scene/saturn/tethys/tethys.mod @@ -8,7 +8,7 @@ return { Body = "TETHYS", Geometry = { Type = "SimpleSphere", - Radius = { 0.538, 3 }, + Radius = 0.538E3, Segments = 50 }, Textures = { diff --git a/data/scene/saturn/titan/titan.mod b/data/scene/saturn/titan/titan.mod index 83e366c7ba..12cc0d6034 100644 --- a/data/scene/saturn/titan/titan.mod +++ b/data/scene/saturn/titan/titan.mod @@ -8,7 +8,7 @@ return { Body = "TITAN", Geometry = { Type = "SimpleSphere", - Radius = { 0.2575, 4 }, + Radius = 0.2575E4, Segments = 50 }, Textures = { diff --git a/data/scene/sun/sun.mod b/data/scene/sun/sun.mod index abe0f87cb9..6905d9de89 100644 --- a/data/scene/sun/sun.mod +++ b/data/scene/sun/sun.mod @@ -20,7 +20,8 @@ return { Body = "SUN", Geometry = { Type = "SimpleSphere", - Radius = { 2.783200, 9 }, + --Radius = 2.783200E9, + Radius = 6.957E8, Segments = 100 }, Textures = { @@ -49,7 +50,7 @@ return { Parent = "SolarSystemBarycenter", Renderable = { Type = "RenderablePlane", - Size = {1.3, 10.5}, + Size = 1.3*10^10.5, Origin = "Center", Billboard = true, Texture = "textures/sun-glare.png", @@ -70,7 +71,7 @@ return { Parent = "Sun", Renderable = { Type = "RenderablePlane", - Size = {3.0, 11.0}, + Size = 3.0E11, Origin = "Center", Billboard = true, Texture = "textures/marker.png", diff --git a/data/scene/uranus/uranus.mod b/data/scene/uranus/uranus.mod index 7d0a559780..f6d8aae2dc 100644 --- a/data/scene/uranus/uranus.mod +++ b/data/scene/uranus/uranus.mod @@ -23,7 +23,7 @@ return { Body = "URANUS BARYCENTER", Geometry = { Type = "SimpleSphere", - Radius = { 2.5362 , 7 }, + Radius = 2.5362E7, Segments = 100 }, Textures = { diff --git a/data/scene/venus/venus.mod b/data/scene/venus/venus.mod index c7943047d3..71e03f2225 100644 --- a/data/scene/venus/venus.mod +++ b/data/scene/venus/venus.mod @@ -23,7 +23,7 @@ return { Body = "VENUS", Geometry = { Type = "SimpleSphere", - Radius = { 3.760, 6 }, + Radius = 3.760E6, Segments = 100 }, Textures = { diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index c4b1e731c2..b2abbb7710 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -28,7 +28,6 @@ #include #include -#include #include #include @@ -72,8 +71,8 @@ public: virtual bool isReady() const = 0; bool isEnabled() const; - void setBoundingSphere(PowerScaledScalar boundingSphere); - PowerScaledScalar getBoundingSphere(); + void setBoundingSphere(float boundingSphere); + float boundingSphere() const; virtual void render(const RenderData& data); virtual void render(const RenderData& data, RendererTasks& rendererTask); @@ -99,7 +98,7 @@ protected: private: RenderBin _renderBin; - PowerScaledScalar boundingSphere_; + float _boundingSphere; std::string _startTime; std::string _endTime; bool _hasTimeInterval; diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index 2b45a9c8d8..76f87a3e41 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -94,11 +94,6 @@ public: */ void update(const UpdateData& data); - /** - * Evaluate if the SceneGraphNodes are visible to the provided camera. - */ - void evaluate(Camera* camera); - /** * Render visible SceneGraphNodes using the provided camera. */ diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 58a1c5a99b..8f9840e51a 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -73,7 +73,6 @@ public: void traversePreOrder(std::function fn); void traversePostOrder(std::function fn); void update(const UpdateData& data); - void evaluate(const Camera* camera, const psc& parentPosition = psc()); void render(const RenderData& data, RendererTasks& tasks); void updateCamera(Camera* camera) const; @@ -103,8 +102,7 @@ public: SceneGraphNode* parent() const; std::vector children() const; - PowerScaledScalar calculateBoundingSphere(); - PowerScaledScalar boundingSphere() const; + float boundingSphere() const; SceneGraphNode* childNode(const std::string& name); @@ -130,10 +128,6 @@ private: PerformanceRecord _performanceRecord; std::unique_ptr _renderable; - bool _renderableVisible; - - bool _boundingSphereVisible; - PowerScaledScalar _boundingSphere; // Transformation defined by ephemeris, rotation and scale struct { diff --git a/include/openspace/util/powerscaledsphere.h b/include/openspace/util/powerscaledsphere.h index 0e51bb4364..7c18782b8c 100644 --- a/include/openspace/util/powerscaledsphere.h +++ b/include/openspace/util/powerscaledsphere.h @@ -38,8 +38,8 @@ public: // initializers PowerScaledSphere(const PowerScaledScalar& radius, int segments = 8); - PowerScaledSphere(properties::Vec4Property &radius, - int segments, std::string planetName); + + PowerScaledSphere(glm::vec3 radius, int segments); ~PowerScaledSphere(); PowerScaledSphere(const PowerScaledSphere& cpy); diff --git a/modules/base/rendering/modelgeometry.cpp b/modules/base/rendering/modelgeometry.cpp index 82e3ee0074..b89461a54e 100644 --- a/modules/base/rendering/modelgeometry.cpp +++ b/modules/base/rendering/modelgeometry.cpp @@ -144,7 +144,7 @@ bool ModelGeometry::initialize(Renderable* parent) { glm::pow(v.location[1], 2.f) + glm::pow(v.location[2], 2.f), maximumDistanceSquared); } - _parent->setBoundingSphere(PowerScaledScalar(glm::sqrt(maximumDistanceSquared), 0.0)); + _parent->setBoundingSphere(glm::sqrt(maximumDistanceSquared)); if (_vertices.empty()) return false; diff --git a/modules/base/rendering/renderableplane.cpp b/modules/base/rendering/renderableplane.cpp index 965ffd0307..b6b362ed7f 100644 --- a/modules/base/rendering/renderableplane.cpp +++ b/modules/base/rendering/renderableplane.cpp @@ -55,7 +55,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) , _texturePath("texture", "Texture") , _billboard("billboard", "Billboard", false) , _projectionListener("projectionListener", "DisplayProjections", false) - , _size("size", "Size", glm::vec2(1,1), glm::vec2(0.f), glm::vec2(1.f, 25.f)) + , _size("size", "Size", 10, 0, std::pow(10, 25)) , _origin(Origin::Center) , _shader(nullptr) , _textureIsDirty(false) @@ -64,9 +64,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) , _quad(0) , _vertexPositionBuffer(0) { - glm::vec2 size; - dictionary.getValue("Size", size); - _size = size; + dictionary.getValue("Size", _size); if (dictionary.hasKey("Name")) { dictionary.getValue("Name", _nodeName); @@ -127,7 +125,7 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) //_size.onChange(std::bind(&RenderablePlane::createPlane, this)); _size.onChange([this](){ _planeIsDirty = true; }); - setBoundingSphere(_size.value()); + setBoundingSphere(_size); } RenderablePlane::~RenderablePlane() { @@ -299,16 +297,15 @@ void RenderablePlane::createPlane() { // ============================ // GEOMETRY (quad) // ============================ - const GLfloat size = _size.value()[0]; - const GLfloat w = _size.value()[1]; + const GLfloat size = _size; const GLfloat vertex_data[] = { // x y z w s t - -size, -size, 0.f, w, 0.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - -size, size, 0.f, w, 0.f, 1.f, - -size, -size, 0.f, w, 0.f, 0.f, - size, -size, 0.f, w, 1.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, + -size, size, 0.f, 0.f, 0.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, -size, 0.f, 0.f, 1.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, }; glBindVertexArray(_quad); // bind array diff --git a/modules/base/rendering/renderableplane.h b/modules/base/rendering/renderableplane.h index 3c26807882..a14e340f9e 100644 --- a/modules/base/rendering/renderableplane.h +++ b/modules/base/rendering/renderableplane.h @@ -29,7 +29,6 @@ #include #include -#include #include namespace ghoul { @@ -75,7 +74,7 @@ private: properties::StringProperty _texturePath; properties::BoolProperty _billboard; properties::BoolProperty _projectionListener; - properties::Vec2Property _size; + properties::FloatProperty _size; Origin _origin; std::string _nodeName; diff --git a/modules/base/rendering/renderablesphericalgrid.cpp b/modules/base/rendering/renderablesphericalgrid.cpp index da602a2c5f..83a7c7c76f 100644 --- a/modules/base/rendering/renderablesphericalgrid.cpp +++ b/modules/base/rendering/renderablesphericalgrid.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #define _USE_MATH_DEFINES #include @@ -39,12 +40,10 @@ namespace { const char* KeyGridSegments = "GridSegments"; const char* KeyGridRadius = "GridRadius"; const char* KeyGridParentsRotation = "ParentsRotation"; + const glm::vec2 GridRadius = { 1.f, 20.f }; } namespace openspace { -// needs to be set from dictionary - REMEMBER -const PowerScaledScalar radius = PowerScaledScalar(1.f, 20.f); - RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _gridProgram(nullptr) @@ -78,7 +77,7 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio int nr = 0; const float fsegments = static_cast(_segments); - const float r = static_cast(radius[0]); + const float r = static_cast(GridRadius[0]); //int nr2 = 0; @@ -117,7 +116,7 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio _varray[nr].location[i] = tmp[i]; _varray[nr].normal[i] = normal[i]; } - _varray[nr].location[3] = static_cast(radius[1]); + _varray[nr].location[3] = static_cast(GridRadius[1]); ++nr; } } diff --git a/modules/base/rendering/renderablesphericalgrid.h b/modules/base/rendering/renderablesphericalgrid.h index 1980018c48..f5290bc1d5 100644 --- a/modules/base/rendering/renderablesphericalgrid.h +++ b/modules/base/rendering/renderablesphericalgrid.h @@ -62,7 +62,6 @@ protected: bool staticGrid; std::string _parentsRotation; glm::dmat3 _parentMatrix; - PowerScaledScalar _radius; GLuint _vaoID = 3; GLuint _vBufferID = 4; diff --git a/modules/debugging/rendering/renderabledebugplane.cpp b/modules/debugging/rendering/renderabledebugplane.cpp index e40dd68cd5..53278c1c42 100644 --- a/modules/debugging/rendering/renderabledebugplane.cpp +++ b/modules/debugging/rendering/renderabledebugplane.cpp @@ -49,15 +49,13 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _texture("texture", "Texture", -1, -1, 255) , _billboard("billboard", "Billboard", false) - , _size("size", "Size", glm::vec2(1,1), glm::vec2(0.f), glm::vec2(1.f, 25.f)) + , _size("size", "Size", 10, 0, std::pow(10, 25)) , _origin(Origin::Center) , _shader(nullptr) , _quad(0) , _vertexPositionBuffer(0) { - glm::vec2 size; - dictionary.getValue("Size", size); - _size = size; + dictionary.getValue("Size", _size); if (dictionary.hasKey("Name")){ dictionary.getValue("Name", _nodeName); @@ -104,7 +102,7 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) addProperty(_size); _size.onChange([this](){ _planeIsDirty = true; }); - setBoundingSphere(_size.value()); + setBoundingSphere(_size); } RenderableDebugPlane::~RenderableDebugPlane() { @@ -189,16 +187,16 @@ void RenderableDebugPlane::createPlane() { // ============================ // GEOMETRY (quad) // ============================ - const GLfloat size = _size.value()[0]; - const GLfloat w = _size.value()[1]; + const GLfloat size = _size; + const GLfloat vertex_data[] = { // x y z w s t - -size, -size, 0.f, w, 0.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - -size, size, 0.f, w, 0.f, 1.f, - -size, -size, 0.f, w, 0.f, 0.f, - size, -size, 0.f, w, 1.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, + -size, size, 0.f, 0.f, 0.f, 1.f, + -size, -size, 0.f, 0.f, 0.f, 0.f, + size, -size, 0.f, 0.f, 1.f, 0.f, + size, size, 0.f, 0.f, 1.f, 1.f, }; glBindVertexArray(_quad); // bind array diff --git a/modules/debugging/rendering/renderabledebugplane.h b/modules/debugging/rendering/renderabledebugplane.h index 96df652354..b007cef5dd 100644 --- a/modules/debugging/rendering/renderabledebugplane.h +++ b/modules/debugging/rendering/renderabledebugplane.h @@ -28,7 +28,6 @@ #include #include -#include #include namespace ghoul { @@ -67,7 +66,7 @@ private: properties::IntProperty _texture; properties::BoolProperty _billboard; - properties::Vec2Property _size; + properties::FloatProperty _size; Origin _origin; std::string _nodeName; diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index 3b2038a056..3426c33330 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -78,7 +78,7 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) glm::dvec3 radii; dictionary.getValue(keyRadii, radii); _ellipsoid = Ellipsoid(radii); - setBoundingSphere(pss(_ellipsoid.averageRadius(), 0.0)); + setBoundingSphere(_ellipsoid.averageRadius()); // Ghoul can't read ints from lua dictionaries... double patchSegmentsd; diff --git a/modules/globebrowsing/other/distanceswitch.cpp b/modules/globebrowsing/other/distanceswitch.cpp index 9bb93cfa96..18f4644643 100644 --- a/modules/globebrowsing/other/distanceswitch.cpp +++ b/modules/globebrowsing/other/distanceswitch.cpp @@ -23,7 +23,6 @@ ****************************************************************************************/ #include - #include namespace openspace { @@ -52,8 +51,7 @@ void DistanceSwitch::render(const RenderData& data) { return; } - pss pssDistanceToCamera = (data.camera.position() - data.position).length(); - double distanceToCamera = pssDistanceToCamera.lengthd(); + double distanceToCamera = (data.camera.positionVec3() - data.position.dvec3()).length(); if (distanceToCamera > _maxDistances.back() * _objectScale) { return; diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp index 36f448f5bc..188e9b915d 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.cpp +++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp @@ -143,7 +143,7 @@ RenderableModelProjection::RenderableModelProjection(const ghoul::Dictionary& di float boundingSphereRadius = 1.0e9; dictionary.getValue(keyBoundingSphereRadius, boundingSphereRadius); - setBoundingSphere(PowerScaledScalar::CreatePSS(boundingSphereRadius)); + setBoundingSphere(boundingSphereRadius); Renderable::addProperty(_performShading); Renderable::addProperty(_rotation); @@ -187,7 +187,7 @@ bool RenderableModelProjection::initialize() { completeSuccess &= loadTextures(); completeSuccess &= _projectionComponent.initializeGL(); - auto bs = getBoundingSphere(); + float bs = boundingSphere(); completeSuccess &= _geometry->initialize(this); setBoundingSphere(bs); // ignore bounding sphere set by geometry. @@ -397,7 +397,7 @@ void RenderableModelProjection::attitudeParameters(double time) { glm::vec3 cpos = position.vec3(); float distance = glm::length(cpos); - float radius = getBoundingSphere().lengthf(); + float radius = boundingSphere(); _projectorMatrix = _projectionComponent.computeProjectorMatrix( cpos, boresight, _up, _instrumentMatrix, diff --git a/modules/newhorizons/rendering/renderableplaneprojection.cpp b/modules/newhorizons/rendering/renderableplaneprojection.cpp index ecf419ce60..e06104368d 100644 --- a/modules/newhorizons/rendering/renderableplaneprojection.cpp +++ b/modules/newhorizons/rendering/renderableplaneprojection.cpp @@ -318,17 +318,4 @@ void RenderablePlaneProjection::setTarget(std::string body) { _target.frame = openspace::SpiceManager::ref().frameFromBody(body); } -std::string RenderablePlaneProjection::findClosestTarget(double currentTime) { - - std::vector targets; - - std::vector nodes = OsEng.renderEngine().scene()->allSceneGraphNodes(); - std::string targetBody; - - PowerScaledScalar min = PowerScaledScalar::CreatePSS(REALLY_FAR); - PowerScaledScalar distance = PowerScaledScalar::CreatePSS(0.0); - - return targetBody; -} - } // namespace openspace diff --git a/modules/newhorizons/rendering/renderableplaneprojection.h b/modules/newhorizons/rendering/renderableplaneprojection.h index 72a5413e5b..d1963b18e6 100644 --- a/modules/newhorizons/rendering/renderableplaneprojection.h +++ b/modules/newhorizons/rendering/renderableplaneprojection.h @@ -68,7 +68,6 @@ public: private: void loadTexture(); void updatePlane(const Image& img, double currentTime); - std::string findClosestTarget(double currentTime); void setTarget(std::string body); std::string _texturePath; diff --git a/modules/newhorizons/rendering/renderableplanetprojection.cpp b/modules/newhorizons/rendering/renderableplanetprojection.cpp index fa495b901c..6e81de5e49 100644 --- a/modules/newhorizons/rendering/renderableplanetprojection.cpp +++ b/modules/newhorizons/rendering/renderableplanetprojection.cpp @@ -177,7 +177,7 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& glm::vec2 radius = glm::vec2(1.0, 9.0); dictionary.getValue(keyRadius, radius); - setBoundingSphere(pss(radius)); + setBoundingSphere(radius[0] * std::pow(10, radius[1])); addPropertySubOwner(_geometry.get()); addPropertySubOwner(_projectionComponent); @@ -356,7 +356,7 @@ void RenderablePlanetProjection::attitudeParameters(double time) { glm::vec3 cpos = position.vec3(); float distance = glm::length(cpos); - float radius = getBoundingSphere().lengthf(); + float radius = boundingSphere(); _projectorMatrix = _projectionComponent.computeProjectorMatrix( cpos, diff --git a/modules/space/rendering/renderableplanet.cpp b/modules/space/rendering/renderableplanet.cpp index 17bdd3c71d..46d114b030 100644 --- a/modules/space/rendering/renderableplanet.cpp +++ b/modules/space/rendering/renderableplanet.cpp @@ -91,19 +91,35 @@ RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) ghoul::Dictionary geometryDictionary; success = dictionary.getValue(keyGeometry, geometryDictionary); - if (success) { - geometryDictionary.setValue(SceneGraphNode::KeyName, name); - _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geometryDictionary); - glm::vec2 planetRadiusVec; - success = geometryDictionary.getValue(keyRadius, planetRadiusVec); - if (success) { - _planetRadius = static_cast( - planetRadiusVec[0] * glm::pow(10, planetRadiusVec[1]) - ); + + glm::dvec3 radius; + bool accutareRadius = false; + try { + SpiceManager::ref().getValue(name, "RADII", radius); + accutareRadius = true; + } catch (const SpiceManager::SpiceException& e) { + accutareRadius = false; + } + + if (accutareRadius) { + radius *= 1000.0; // Spice gives radii in KM. + std::swap(radius[1], radius[2]); // z is equivalent to y in our coordinate system + geometryDictionary.setValue(keyRadius, radius); + } + + if (success) { + //geometryDictionary.setValue(SceneGraphNode::KeyName, name); + _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geometryDictionary); + + float planetRadius; + if (accutareRadius) { + _planetRadius = (radius[0] + radius[1] + radius[2]) / 3.0; + } else if (geometryDictionary.getValue(keyRadius, planetRadius)) { + _planetRadius = planetRadius; } else { - LWARNING("No Radius value expecified for " << name << " planet."); + LWARNING("No Radius value specified for " << name << " planet."); } } @@ -168,13 +184,13 @@ RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) ss << keyShadowSource << sourceCounter << ".Name"; success = shadowDictionary.getValue(ss.str(), sourceName); if (success) { - glm::vec2 sourceRadius; + float sourceRadius; ss.str(std::string()); ss << keyShadowSource << sourceCounter << ".Radius"; success = shadowDictionary.getValue(ss.str(), sourceRadius); if (success) { sourceArray.push_back(std::pair< std::string, float>( - sourceName, sourceRadius[0] * pow(10.f, sourceRadius[1]))); + sourceName, sourceRadius)); } else { LWARNING("No Radius value expecified for Shadow Source Name " @@ -197,13 +213,13 @@ RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) ss << keyShadowCaster << casterCounter << ".Name"; success = shadowDictionary.getValue(ss.str(), casterName); if (success) { - glm::vec2 casterRadius; + float casterRadius; ss.str(std::string()); ss << keyShadowCaster << casterCounter << ".Radius"; success = shadowDictionary.getValue(ss.str(), casterRadius); if (success) { casterArray.push_back(std::pair< std::string, float>( - casterName, casterRadius[0] * pow(10.f, casterRadius[1]))); + casterName, casterRadius)); } else { LWARNING("No Radius value expecified for Shadow Caster Name " diff --git a/modules/space/rendering/renderablerings.cpp b/modules/space/rendering/renderablerings.cpp index 1e16d2d838..ba24a5a556 100644 --- a/modules/space/rendering/renderablerings.cpp +++ b/modules/space/rendering/renderablerings.cpp @@ -106,7 +106,7 @@ RenderableRings::RenderableRings(const ghoul::Dictionary& dictionary) ); _size = static_cast(dictionary.value(KeySize)); - setBoundingSphere(PowerScaledScalar::CreatePSS(_size)); + setBoundingSphere(_size); addProperty(_size); _size.onChange([&]() { _planeIsDirty = true; }); diff --git a/modules/space/rendering/simplespheregeometry.cpp b/modules/space/rendering/simplespheregeometry.cpp index 03d5aefbb8..4b4eef96ec 100644 --- a/modules/space/rendering/simplespheregeometry.cpp +++ b/modules/space/rendering/simplespheregeometry.cpp @@ -43,51 +43,47 @@ namespace planetgeometry { SimpleSphereGeometry::SimpleSphereGeometry(const ghoul::Dictionary& dictionary) : PlanetGeometry() - , _realRadius("radius", "Radius", glm::vec4(1.f, 1.f, 1.f, 0.f), glm::vec4(-10.f, -10.f, -10.f, -20.f), - glm::vec4(10.f, 10.f, 10.f, 20.f)) + , _radius( + "radius", + "Radius", + glm::vec3(1.f, 1.f, 1.f), + glm::vec3(0.f, 0.f, 0.f), + glm::vec3(std::pow(10.f, 20.f), std::pow(10.f, 20.f), std::pow(10.f, 20.f))) , _segments("segments", "Segments", 20, 1, 5000) , _sphere(nullptr) { using constants::simplespheregeometry::keyRadius; using constants::simplespheregeometry::keySegments; - // The name is passed down from the SceneGraphNode - bool success = dictionary.getValue(SceneGraphNode::KeyName, _name); - assert(success); - - glm::vec4 radius; - success = dictionary.getValue(keyRadius, _modRadius); - if (!success) { - LERROR("SimpleSphereGeometry of '" << _name << "' did not provide a key '" - << keyRadius << "'"); - } - else { - radius[0] = _modRadius[0]; - radius[1] = _modRadius[0]; - radius[2] = _modRadius[0]; - radius[3] = _modRadius[1]; - _realRadius = radius; // In case the kernels does not supply a real + float sphereRadius = 0.f; + glm::vec3 ellipsoidRadius; + if (dictionary.getValue(keyRadius, sphereRadius)) { + _radius = { sphereRadius, sphereRadius, sphereRadius }; + } else if (dictionary.getValue(keyRadius, ellipsoidRadius)) { + _radius = ellipsoidRadius; + } else { + LERROR("SimpleSphereGeometry did not provide a key '" + << keyRadius << "'"); } - double segments; - success = dictionary.getValue(keySegments, segments); - if (!success) { - LERROR("SimpleSphereGeometry of '" << _name << "' did not provide a key '" - << keySegments << "'"); - } - else + double segments = 0; + if (dictionary.getValue(keySegments, segments)) { _segments = static_cast(segments); + } else { + LERROR("SimpleSphereGeometry did not provide a key '" + << keySegments << "'"); + } + // The shader need the radii values but they are not changeable runtime // TODO: Possibly add a scaling property @AA - addProperty(_realRadius); + addProperty(_radius); // Changing the radius/scaling should affect the shader but not the geometry? @AA - //_radius.onChange(std::bind(&SimpleSphereGeometry::createSphere, this)); + _radius.onChange(std::bind(&SimpleSphereGeometry::createSphere, this)); addProperty(_segments); _segments.onChange(std::bind(&SimpleSphereGeometry::createSphere, this)); } -SimpleSphereGeometry::~SimpleSphereGeometry() -{ +SimpleSphereGeometry::~SimpleSphereGeometry() { } bool SimpleSphereGeometry::initialize(Renderable* parent) @@ -97,28 +93,24 @@ bool SimpleSphereGeometry::initialize(Renderable* parent) return success; } -void SimpleSphereGeometry::deinitialize() -{ +void SimpleSphereGeometry::deinitialize() { if (_sphere) delete _sphere; _sphere = nullptr; } -void SimpleSphereGeometry::render() -{ +void SimpleSphereGeometry::render() { _sphere->render(); } void SimpleSphereGeometry::createSphere(){ - //create the power scaled scalar - - PowerScaledScalar planetSize(_modRadius); - _parent->setBoundingSphere(planetSize); + const glm::vec3 radius = _radius.value(); + _parent->setBoundingSphere(std::max(std::max(radius[0], radius[1]), radius[2])); if(_sphere) delete _sphere; - //_sphere = new PowerScaledSphere(planetSize, _segments); - _sphere = new PowerScaledSphere(_realRadius, _segments, _name); + + _sphere = new PowerScaledSphere(glm::vec4(radius, 0.0), _segments); _sphere->initialize(); } diff --git a/modules/space/rendering/simplespheregeometry.h b/modules/space/rendering/simplespheregeometry.h index 35740746df..b0525a8ad3 100644 --- a/modules/space/rendering/simplespheregeometry.h +++ b/modules/space/rendering/simplespheregeometry.h @@ -28,7 +28,7 @@ #include #include -#include +#include namespace openspace { @@ -42,20 +42,15 @@ public: SimpleSphereGeometry(const ghoul::Dictionary& dictionary); ~SimpleSphereGeometry(); - bool initialize(Renderable* parent) override; void deinitialize() override; void render() override; - PowerScaledSphere* _planet; - private: void createSphere(); - glm::vec2 _modRadius; - properties::Vec4Property _realRadius; + float _modRadius; + properties::Vec3Property _radius; properties::IntProperty _segments; - std::string _name; - PowerScaledSphere* _sphere; }; diff --git a/src/interaction/interactionmode.cpp b/src/interaction/interactionmode.cpp index 44cbfa23bf..69ae7eb27e 100644 --- a/src/interaction/interactionmode.cpp +++ b/src/interaction/interactionmode.cpp @@ -401,7 +401,7 @@ void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera, do dquat totalRotation = camera.rotationQuaternion(); dvec3 directionToCenter = normalize(centerPos - camPos); dvec3 lookUp = camera.lookUpVectorWorldSpace(); - double boundingSphere = _focusNode->boundingSphere().lengthf(); + double boundingSphere = _focusNode->boundingSphere(); dvec3 camDirection = camera.viewDirectionWorldSpace(); // Declare other variables used in interaction calculations diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index ab22ebe710..6da8f4a0dc 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -121,12 +121,12 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) Renderable::~Renderable() {} -void Renderable::setBoundingSphere(PowerScaledScalar boundingSphere) { - boundingSphere_ = std::move(boundingSphere); +void Renderable::setBoundingSphere(float boundingSphere) { + _boundingSphere = boundingSphere; } -PowerScaledScalar Renderable::getBoundingSphere() { - return boundingSphere_; +float Renderable::boundingSphere() const { + return _boundingSphere; } void Renderable::update(const UpdateData&) {} diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index d1cd2e6456..dfc2f9b55c 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -282,8 +282,6 @@ void RenderEngine::updateScene() { Time::ref().timeJumped(), _performanceManager != nullptr }); - - _scene->evaluate(_camera); LTRACE("RenderEngine::updateSceneGraph(end)"); } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 206c0a325f..6611fc236e 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -228,19 +228,6 @@ void Scene::update(const UpdateData& data) { } } -void Scene::evaluate(Camera* camera) { - for (SceneGraphNode* node : _topologicallySortedNodes) { - try { - LTRACE("Scene::evaluate(begin '" + node->name() + "')"); - node->evaluate(camera); - LTRACE("Scene::evaluate(end '" + node->name() + "')"); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.what()); - } - } -} - void Scene::render(const RenderData& data, RendererTasks& tasks) { for (SceneGraphNode* node : _topologicallySortedNodes) { try { diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 5538d3187b..cc5780bb1b 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -151,8 +151,6 @@ SceneGraphNode::SceneGraphNode() } , _performanceRecord({0, 0, 0}) , _renderable(nullptr) - , _renderableVisible(false) - , _boundingSphereVisible(false) { } @@ -190,9 +188,6 @@ bool SceneGraphNode::deinitialize() { // reset variables _parent = nullptr; - _renderableVisible = false; - _boundingSphereVisible = false; - _boundingSphere = PowerScaledScalar(0.0, 0.0); return true; } @@ -286,46 +281,6 @@ void SceneGraphNode::update(const UpdateData& data) { } } -void SceneGraphNode::evaluate(const Camera* camera, const psc& parentPosition) { - //const psc thisPosition = parentPosition + _ephemeris->position(); - //const psc camPos = camera->position(); - //const psc toCamera = thisPosition - camPos; - - // init as not visible - //_boundingSphereVisible = false; - _renderableVisible = false; - -#ifndef OPENSPACE_VIDEO_EXPORT - // check if camera is outside the node boundingsphere - /* if (toCamera.length() > _boundingSphere) { - // check if the boudningsphere is visible before avaluating children - if (!sphereInsideFrustum(thisPosition, _boundingSphere, camera)) { - // the node is completely outside of the camera view, stop evaluating this - // node - //LFATAL(_nodeName << " is outside of frustum"); - return; - } - } - */ -#endif - - // inside boudningsphere or parts of the sphere is visible, individual - // children needs to be evaluated - _boundingSphereVisible = true; - - // this node has an renderable - if (_renderable) { - // check if the renderable boundingsphere is visible - // _renderableVisible = sphereInsideFrustum( - // thisPosition, _renderable->getBoundingSphere(), camera); - _renderableVisible = true; - } - - // evaluate all the children, tail-recursive function(?) - //for (SceneGraphNode* child : _children) - // child->evaluate(camera, psc()); -} - void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { const psc thisPositionPSC = psc::CreatePowerScaledCoordinate(_worldPositionCached.x, _worldPositionCached.y, _worldPositionCached.z); @@ -340,7 +295,7 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { //_performanceRecord.renderTime = 0; - bool visible = _renderableVisible && + bool visible = _renderable && _renderable->isVisible() && _renderable->isReady() && _renderable->isEnabled() && @@ -582,42 +537,11 @@ std::vector SceneGraphNode::children() const { return nodes; } -PowerScaledScalar SceneGraphNode::calculateBoundingSphere(){ - // set the bounding sphere to 0.0 - _boundingSphere = 0.0; - /* - This is not how to calculate a bounding sphere, better to leave it at 0 if not a - renderable. --KB - if (!_children.empty()) { // node - PowerScaledScalar maxChild; - - // loop though all children and find the one furthest away/with the largest - // bounding sphere - for (size_t i = 0; i < _children.size(); ++i) { - // when positions is dynamic, change this part to fins the most distant - // position - //PowerScaledScalar child = _children.at(i)->position().length() - // + _children.at(i)->calculateBoundingSphere(); - PowerScaledScalar child = _children.at(i)->calculateBoundingSphere(); - if (child > maxChild) { - maxChild = child; - } - } - _boundingSphere += maxChild; - } - */ - // if has a renderable, use that boundingsphere - if (_renderable ) { - PowerScaledScalar renderableBS = _renderable->getBoundingSphere(); - if(renderableBS > _boundingSphere) - _boundingSphere = renderableBS; +float SceneGraphNode::boundingSphere() const{ + if (_renderable) { + return _renderable->boundingSphere(); } - - return _boundingSphere; -} - -PowerScaledScalar SceneGraphNode::boundingSphere() const{ - return _boundingSphere; + return 0.0; } // renderable diff --git a/src/util/powerscaledsphere.cpp b/src/util/powerscaledsphere.cpp index 9d646a78ec..3f3c96904c 100644 --- a/src/util/powerscaledsphere.cpp +++ b/src/util/powerscaledsphere.cpp @@ -24,7 +24,6 @@ // open space includes #include -#include #include #define _USE_MATH_DEFINES @@ -126,7 +125,7 @@ PowerScaledSphere::PowerScaledSphere(const PowerScaledScalar& radius, int segmen } // Alternative Constructor for using accurate triaxial ellipsoid -PowerScaledSphere::PowerScaledSphere(properties::Vec4Property &radius, int segments, std::string planetName) +PowerScaledSphere::PowerScaledSphere(glm::vec3 radius, int segments) : _vaoID(0) , _vBufferID(0) , _iBufferID(0) @@ -137,42 +136,7 @@ PowerScaledSphere::PowerScaledSphere(properties::Vec4Property &radius, int segme { static_assert(sizeof(Vertex) == 64, "The size of the Vertex needs to be 64 for performance"); - - float a, b, c, powerscale; - bool accutareRadius; - try { - glm::dvec3 radii; - SpiceManager::ref().getValue(planetName, "RADII", radii); - a = radii.x; - b = radii.y; - c = radii.z; - accutareRadius = true; - } - catch (const SpiceManager::SpiceException& e) { - //LINFO("Could not find radius for body " << planetName); - accutareRadius = false; - } - - if (accutareRadius) { - PowerScaledCoordinate powerScaledRadii = psc::CreatePowerScaledCoordinate(a, b, c); - powerScaledRadii[3] += 3; // SPICE returns radii in km - - std::swap(powerScaledRadii[1], powerScaledRadii[2]); // c is equivalent to y in our coordinate system - radius.set(powerScaledRadii.vec4()); - a = powerScaledRadii[0]; - b = powerScaledRadii[1]; - c = powerScaledRadii[2]; - powerscale = powerScaledRadii[3]; - } - else { - ghoul::any r = radius.get(); - glm::vec4 modRadius = ghoul::any_cast(r); - a = modRadius[0]; - b = modRadius[1]; - c = modRadius[2]; - powerscale = modRadius[3]; - } - + int nr = 0; const float fsegments = static_cast(segments); @@ -186,14 +150,14 @@ PowerScaledSphere::PowerScaledSphere(properties::Vec4Property &radius, int segme // azimuth angle (east to west) const float phi = fj * float(M_PI) * 2.0f / fsegments; // 0 -> 2*PI - const float x = a * sin(phi) * sin(theta); // - const float y = b * cos(theta); // up - const float z = c * cos(phi) * sin(theta); // + const float x = radius[0] * sin(phi) * sin(theta); // + const float y = radius[1] * cos(theta); // up + const float z = radius[2] * cos(phi) * sin(theta); // _varray[nr].location[0] = x; _varray[nr].location[1] = y; _varray[nr].location[2] = z; - _varray[nr].location[3] = powerscale; + _varray[nr].location[3] = 0.0; glm::vec3 normal = glm::vec3(x, y, z); if (!(x == 0.f && y == 0.f && z == 0.f)) From 47535e38f96b7750f9258a556ff4f464f6db913c Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Apr 2017 16:20:20 -0600 Subject: [PATCH 054/192] func and grad should now be defined correctly, needs to be tested --- modules/touch/include/TouchInteraction.h | 11 ++ modules/touch/src/TouchInteraction.cpp | 203 ++++++++++++++++++----- src/query/query.cpp | 4 +- 3 files changed, 174 insertions(+), 44 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index f7673ebf2a..14d7fac4f5 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -45,6 +45,7 @@ #endif #include +#include #define ROT 0 #define PINCH 1 @@ -81,6 +82,16 @@ struct SelectedBody { glm::dvec3 coordinates; }; +struct FunctionData { + Camera* camera; + SceneGraphNode* node; + double aspectRatio; + double* measurements; + int nDOF; + //std::function toScreen; + //std::function toSurface; +}; + using Point = std::pair; class TouchInteraction : public properties::PropertyOwner diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 2a5b16888c..277c3d2663 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -82,68 +82,187 @@ TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { if (_directTouchMode) { // should just be a function call - /* - 1, define s(xi,q): newXi = T(tx,ty,tz)Q(rx,ry,rz)xi, s(xi,q) = modelToScreenSpace(newXi) - 2, calculate minimum error E = sum( ||s(xi,q)-pi||^2 ) (and define q in the process) - * xi is the old modelview position (_selected.at(i).coordinates), - * q the 6DOF vector (Trans(x,y,z)Quat(x,y,z)) to be defined that will move xi to a new pos, - * pi the current point in screen space (list.at(i).getXY) - 3, Do the inverse rotation of M(q) on the camera, map interactions to different number of direct touch points - */ - // define these according to the M(q) - auto func = [](double* par, int x, void* fdata) { // par is the vector of measurements, x current point par[x], fdata additional data needed by the function - // define s(xi, q) : newXi = T(tx, ty, tz)Q(rx, ry, rz)xi, s(xi, q) = modelToScreenSpace(newXi) - glm::dvec2 screenPoint; - if (x % 2) { // true = par[x] is a y-coord, false = par[x] is an x-coord - screenPoint.x = par[x-1]; - screenPoint.y = par[x]; + + // Returns the new value of screen point measurements[x] according to the transform M(par) + auto func = [](double* par, int x, void* fdata) { // par is the 6DOF vector , x the id of the measurements measurements[x], fdata additional data needed by the function + auto toSurface = [](int x, FunctionData* ptr) { + glm::dvec2 screenPoint; + if (x % 2) { // true = y[x] is a y-coord, false = y[x] is an x-coord + screenPoint.x = ptr->measurements[x - 1]; + screenPoint.y = ptr->measurements[x]; + } + else { + screenPoint.x = ptr->measurements[x]; + screenPoint.y = ptr->measurements[x + 1]; + } + + // Find the intersection point in surface coordinates again; + glm::dvec3 camPos = ptr->camera->positionVec3(); + double xCo = 2 * (screenPoint.x - 0.5) * ptr->aspectRatio; + double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen + glm::dvec3 raytrace = glm::normalize(ptr->camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); + glm::dvec3 camToSelectable = ptr->node->worldPosition() - camPos; + double boundingSphere = ptr->node->boundingSphere().lengthd(); + double d = glm::dot(raytrace, camToSelectable); + double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; + if (root > 0) // two intersection points (take the closest one) + d -= sqrt(root); + glm::dvec3 intersectionPoint = camPos + d * raytrace; + return (glm::inverse(ptr->node->rotationMatrix()) * (intersectionPoint - ptr->node->worldPosition())); + }; + auto toScreen = [](glm::dvec3 vec, FunctionData* ptr) { + glm::dvec3 backToScreenSpace = glm::inverse(ptr->camera->rotationQuaternion()) + * glm::normalize(((ptr->node->rotationMatrix() * vec) + ptr->node->worldPosition() - ptr->camera->positionVec3())); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + return glm::dvec2(backToScreenSpace.x / (2 * ptr->aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); + }; + + FunctionData* ptr = reinterpret_cast(fdata); + glm::dvec3 surfacePoint = toSurface(x, ptr); // get current screen point from the id "x". + + // Create transformation matrix M(q) and apply transform for newPointInModelView + glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); + glm::dquat Q; + Q.x = Q.y = Q.z = 0.0; + if (ptr->nDOF > 2) { // need to check how many DOF we can handle (+2 DOF per finger down up to 6) + T.z = par[2]; + Q.x = par[3]; + if (ptr->nDOF > 4) { + Q.y = par[4]; + Q.z = par[5]; + } } - else { - screenPoint.x = par[x]; - screenPoint.y = par[x+1]; - } - // fdata has to contain aspectRatio, camera and node, - //glm::dvec3 modelPoint = screenToModelSpace(screenPoint); - // create transformation matrix M(q) - //glm::dmat3 T; - //glm::dquat Q; - glm::dvec2 newScreenPoint; //= modelToScreenSpace(T * (Q * modelPoint)); - if (x % 2) + double len = Q.x*Q.x + Q.y*Q.y + Q.z*Q.z; + Q.w = sqrt(1 - len); + glm::dvec3 newSurfacePoint = T + (Q * surfacePoint); + + glm::dvec2 newScreenPoint = toScreen(newSurfacePoint, ptr); // go back to screen-space + + if (x % 2) // return right variable return newScreenPoint.y; else return newScreenPoint.x; }; + // Gradient of func auto grad = [](double* g, double* par, int x, void* fdata) { - g[0] = 1.0 + exp(-par[2] * x); - g[1] = exp(-par[2] * x); - g[2] = -x * (par[1] - par[0]) * exp(-par[2] * x); + auto toSurface = [](int x, FunctionData* ptr) { + glm::dvec2 screenPoint; + if (x % 2) { // true = y[x] is a y-coord, false = y[x] is an x-coord + screenPoint.x = ptr->measurements[x - 1]; + screenPoint.y = ptr->measurements[x]; + } + else { + screenPoint.x = ptr->measurements[x]; + screenPoint.y = ptr->measurements[x + 1]; + } + + // Find the intersection point in surface coordinates again; + glm::dvec3 camPos = ptr->camera->positionVec3(); + double xCo = 2 * (screenPoint.x - 0.5) * ptr->aspectRatio; + double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen + glm::dvec3 raytrace = glm::normalize(ptr->camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); + glm::dvec3 camToSelectable = ptr->node->worldPosition() - camPos; + double boundingSphere = ptr->node->boundingSphere().lengthd(); + double d = glm::dot(raytrace, camToSelectable); + double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; + if (root > 0) // two intersection points (take the closest one) + d -= sqrt(root); + glm::dvec3 intersectionPoint = camPos + d * raytrace; + return (glm::inverse(ptr->node->rotationMatrix()) * (intersectionPoint - ptr->node->worldPosition())); + }; + auto toScreen = [](glm::dvec3 vec, FunctionData* ptr) { + glm::dvec3 backToScreenSpace = glm::inverse(ptr->camera->rotationQuaternion()) + * glm::normalize(((ptr->node->rotationMatrix() * vec) + ptr->node->worldPosition() - ptr->camera->positionVec3())); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + return glm::dvec2(backToScreenSpace.x / (2 * ptr->aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); + }; + + FunctionData* ptr = reinterpret_cast(fdata); + g[0] = 1.0; + g[1] = 1.0; + if (ptr->nDOF > 2) { + g[2] = 1.0; + // Get current screen point from the id "x". + glm::dvec3 surfacePoint = toSurface(x, ptr); + + glm::dquat Q; + Q.x = par[3]; + Q.y = Q.z = 0.0; + if (ptr->nDOF > 4) { + Q.y = par[4]; + Q.z = par[5]; + } + double len = Q.x*Q.x + Q.y*Q.y + Q.z*Q.z; + Q.w = sqrt(1 - len); + + // We now got surface point, need to calculate Q' w.r.t x, y and z and calculate each gradient vector -> transform back to modelview to get g[3]-g[5] + glm::dvec3 gradX; // derivative of Q w.r.t x + gradX.x = surfacePoint.x - 2.0 * Q.y * surfacePoint.y + 2.0 * Q.z * surfacePoint.z; + gradX.y = 2.0 * Q.y * surfacePoint.x + (1.0 - 4.0 * Q.x) * surfacePoint.y + 2.0 * Q.w * surfacePoint.z; + gradX.z = 2.0 * Q.z * surfacePoint.x + 2.0 * Q.w * surfacePoint.y + 2.0 * (1.0 - 4.0 * Q.x) * surfacePoint.z; + + glm::dvec2 newSPx = toScreen(gradX, ptr); + if (x % 2) + g[3] = newSPx.y; + else + g[3] = newSPx.x; + + if (ptr->nDOF > 4) { + glm::dvec3 gradY; // derivative of Q w.r.t y + gradY.x = (1.0 - 4.0 * Q.y) * surfacePoint.x + 2.0 * Q.x * surfacePoint.y + 2.0 * Q.w * surfacePoint.z; + gradY.y = 2.0 * Q.x * surfacePoint.x + surfacePoint.y + 2.0 * Q.z * surfacePoint.z; + gradY.z = -2.0 * Q.w * surfacePoint.x + 2.0 * Q.z * surfacePoint.y + (1.0 - 4.0 * Q.y) * surfacePoint.z; + + glm::dvec3 gradZ; // derivative of Q w.r.t z + gradZ.x = (1.0 - 4.0 * Q.z) * surfacePoint.x - 2.0 * Q.w * surfacePoint.y + 2.0 * Q.x * surfacePoint.z; + gradZ.y = 2.0 * Q.w * surfacePoint.x + (1.0 - 4.0 * Q.z) * surfacePoint.y + 2.0 * Q.y * surfacePoint.z; + gradZ.z = 2.0 * Q.x * surfacePoint.x + 2.0 * Q.y * surfacePoint.y + surfacePoint.z; + + glm::dvec2 newSPy = toScreen(gradY, ptr); + glm::dvec2 newSPz = toScreen(gradZ, ptr); + + if (x % 2) { + g[4] = newSPy.y; + g[5] = newSPz.y; + } + else { + g[4] = newSPy.x; + g[5] = newSPz.x; + } + } + } }; - - const int nDOF = 6; // 6 degrees of freedom - //glm::dquat quat = glm::quat_cast(_selected.at(0).node->rotationMatrix()); - //glm::dvec3 trans = _sekected.at(0).node->worldPosition(); - double q[nDOF] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // initial values of q or 0.0? (ie current model or no rotation/translation) - const int nFingers = _selected.size() * 2; - double* contactPoints = new double[nFingers]; - double* squaredError = new double[nFingers]; + const int nCoord = _selected.size() * 2; + int nDOF = std::min(nCoord, 6); + double* par = new double[nDOF]; + for (int i = 0; i < nDOF; ++i) // initial values of q or 0.0? (ie current model or no rotation/translation) + par[i] = 0.0; + double* screenPoints = new double[nCoord]; + double* squaredError = new double[nCoord]; int i = 0; for (const SelectedBody& sb : _selected) { glm::dvec2 screenPoint = modelToScreenSpace(sb); // transform to screen-space, old point to correct to current - contactPoints[i] = screenPoint.x; - contactPoints[i + 1] = screenPoint.y; + screenPoints[i] = screenPoint.x; + screenPoints[i + 1] = screenPoint.y; std::vector::const_iterator cursor = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return sb.id == c.getSessionID(); }); squaredError[i] = pow(screenPoint.x - cursor->getX(), 2); // squared error to calculate weighted least-square squaredError[i + 1] = pow(screenPoint.y - cursor->getY(), 2); - i += 2; } + glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + + FunctionData fData = { _camera, _selected.at(0).node, res.x / res.y, screenPoints, nDOF }; + void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); - int nIterations = levmarq(nDOF, q, nFingers, contactPoints, squaredError, func, grad, NULL, &_lmstat); // NULL should send fdata(camera, node, aspectRatio) - delete[] contactPoints; + bool success = levmarq(nDOF, par, nCoord, screenPoints, squaredError, func, grad, dataPtr, &_lmstat); // finds best transform values and stores them in par + + // cleanup + delete[] screenPoints; delete[] squaredError; + delete[] par; } //else { trace(list); diff --git a/src/query/query.cpp b/src/query/query.cpp index 47c8e54ff8..1eb2db2988 100644 --- a/src/query/query.cpp +++ b/src/query/query.cpp @@ -115,8 +115,8 @@ std::vector allProperties() { std::vector props = n->propertiesRecursive(); properties.insert( properties.end(), - p.begin(), - p.end() + props.begin(), + props.end() ); } From 99c5956588b07213e18d5b2593a2ed096e28d6b7 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Apr 2017 16:56:55 -0600 Subject: [PATCH 055/192] merge with feature/planetradius for boundingSphere --- modules/touch/ext/levmarq.cpp | 2 +- modules/touch/include/TouchInteraction.h | 3 -- modules/touch/src/TouchInteraction.cpp | 46 +++++++++--------------- 3 files changed, 18 insertions(+), 33 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 7b0ff125ad..50fb947047 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -155,7 +155,7 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, delete[] delta; delete[] newpar; - return (it==nit); + return it; } diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 14d7fac4f5..c82018d438 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -45,7 +45,6 @@ #endif #include -#include #define ROT 0 #define PINCH 1 @@ -88,8 +87,6 @@ struct FunctionData { double aspectRatio; double* measurements; int nDOF; - //std::function toScreen; - //std::function toSurface; }; using Point = std::pair; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 277c3d2663..33767c716c 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -81,8 +81,8 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - if (_directTouchMode) { // should just be a function call - + if (_directTouchMode && _selected.size() > 0) { // should just be a function call + // Returns the new value of screen point measurements[x] according to the transform M(par) auto func = [](double* par, int x, void* fdata) { // par is the 6DOF vector , x the id of the measurements measurements[x], fdata additional data needed by the function auto toSurface = [](int x, FunctionData* ptr) { @@ -102,7 +102,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); glm::dvec3 camToSelectable = ptr->node->worldPosition() - camPos; - double boundingSphere = ptr->node->boundingSphere().lengthd(); + double boundingSphere = ptr->node->boundingSphere(); double d = glm::dot(raytrace, camToSelectable); double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; if (root > 0) // two intersection points (take the closest one) @@ -162,7 +162,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); glm::dvec3 camToSelectable = ptr->node->worldPosition() - camPos; - double boundingSphere = ptr->node->boundingSphere().lengthd(); + double boundingSphere = ptr->node->boundingSphere(); double d = glm::dot(raytrace, camToSelectable); double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; if (root > 0) // two intersection points (take the closest one) @@ -233,7 +233,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

(&fData); levmarq_init(&_lmstat); - bool success = levmarq(nDOF, par, nCoord, screenPoints, squaredError, func, grad, dataPtr, &_lmstat); // finds best transform values and stores them in par + bool nIterations = levmarq(nDOF, par, nCoord, screenPoints, squaredError, func, grad, dataPtr, &_lmstat); // finds best transform values and stores them in par + + + std::ostringstream os; + for (int i = 0; i < nDOF; ++i) { + os << par[i] << ", "; + } + std::cout << "Levmarq success after " << nIterations << ", Print par[nDOF]: " << os.str() << "\n"; // cleanup delete[] screenPoints; @@ -302,7 +308,7 @@ void TouchInteraction::trace(const std::vector& list) { glm::dvec3 raytrace = glm::normalize(cursorInWorldSpace); int id = c.getSessionID(); for (SceneGraphNode* node : selectableNodes) { - double boundingSphere = node->boundingSphere().lengthd(); + double boundingSphere = node->boundingSphere(); glm::dvec3 camToSelectable = node->worldPosition() - camPos; double dist = length(glm::cross(cursorInWorldSpace, camToSelectable)) / glm::length(cursorInWorldSpace) - boundingSphere; if (dist <= 0.0) { @@ -333,24 +339,6 @@ void TouchInteraction::trace(const std::vector& list) { } } - /* - Direct-touch: - 1, we have the touched position on the surface in spherical coordinates - 2, we get new input on new pos - 3, move camera so _selected.coordinates == new pos, cant overwrite _selected then - - Paper: - position in screen-space: p = s(x,q) = h(PM(q)x) - h = combinedViewMatrix - P = projectionmatrix - M(q) = parameterized matrix by the vector q which maps x into worldspace, most likely the product of several matrices which are - parameterized by the transform values (e.g., rotation, scaling, translation, etc.) - x = position in modelview - - minimize error E = sum( ||s(xi,q)-pi||^2 ) (distance between last point p and current x in screen-space) - q is the rotation/translation that is done on the object to match the equation. How do we translate that to camera rot/trans? - */ - //debugging for (auto it : newSelected) { std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; @@ -481,13 +469,13 @@ void TouchInteraction::accelerate(const std::vector& list, const std _vel.localRot = _sensitivity.localRot * glm::dvec2(-angleX, -angleY); } else { // should zoom in to current _selected.coordinates position - double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere().lengthd(); - double startDecline = _focusNode->boundingSphere().lengthd() / (0.15 * _projectionScaleFactor); + double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); + double startDecline = _focusNode->boundingSphere() / (0.15 * _projectionScaleFactor); double factor = 2.0; if (dist < startDecline) { factor = 1.0 + std::pow(dist / startDecline, 2); } - double response = _focusNode->boundingSphere().lengthd() / (factor * _currentRadius * _projectionScaleFactor); + double response = _focusNode->boundingSphere() / (factor * _currentRadius * _projectionScaleFactor); _vel.zoom = _sensitivity.zoom * response; } @@ -517,7 +505,7 @@ void TouchInteraction::step(double dt) { dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); - double boundingSphere = _focusNode->boundingSphere().lengthd(); + double boundingSphere = _focusNode->boundingSphere(); double minHeightAboveBoundingSphere = 1; dvec3 centerToBoundingSphere; From 626c39b62ecf6032519b96148147d9d1f3dccde6 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Apr 2017 16:59:34 -0600 Subject: [PATCH 056/192] fix number of iterations --- modules/touch/ext/levmarq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 50fb947047..34c8c0a460 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -155,7 +155,7 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, delete[] delta; delete[] newpar; - return it; + return (it+1); } From 3635bbcefc81abeb6158f9935480b123c7fa0a6a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 14 Apr 2017 12:02:11 -0600 Subject: [PATCH 057/192] start testing levmarq use --- modules/touch/ext/levmarq.cpp | 2 +- modules/touch/include/TouchInteraction.h | 2 + modules/touch/src/TouchInteraction.cpp | 112 +++++++++-------------- 3 files changed, 47 insertions(+), 69 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 34c8c0a460..365c2cacbd 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,7 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 0; + lmstat->verbose = 1; lmstat->max_it = 10000; lmstat->init_lambda = 0.0001; lmstat->up_factor = 10; diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index c82018d438..acd91b1e19 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -87,6 +87,8 @@ struct FunctionData { double aspectRatio; double* measurements; int nDOF; + glm::dvec2(*toScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); + glm::dvec3(*toSurface)(glm::dvec2, Camera*, SceneGraphNode*, double); }; using Point = std::pair; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 33767c716c..4fec697cc6 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -85,40 +85,17 @@ void TouchInteraction::update(const std::vector& list, std::vector

measurements[x - 1]; - screenPoint.y = ptr->measurements[x]; - } - else { - screenPoint.x = ptr->measurements[x]; - screenPoint.y = ptr->measurements[x + 1]; - } - - // Find the intersection point in surface coordinates again; - glm::dvec3 camPos = ptr->camera->positionVec3(); - double xCo = 2 * (screenPoint.x - 0.5) * ptr->aspectRatio; - double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen - glm::dvec3 raytrace = glm::normalize(ptr->camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); - glm::dvec3 camToSelectable = ptr->node->worldPosition() - camPos; - double boundingSphere = ptr->node->boundingSphere(); - double d = glm::dot(raytrace, camToSelectable); - double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; - if (root > 0) // two intersection points (take the closest one) - d -= sqrt(root); - glm::dvec3 intersectionPoint = camPos + d * raytrace; - return (glm::inverse(ptr->node->rotationMatrix()) * (intersectionPoint - ptr->node->worldPosition())); - }; - auto toScreen = [](glm::dvec3 vec, FunctionData* ptr) { - glm::dvec3 backToScreenSpace = glm::inverse(ptr->camera->rotationQuaternion()) - * glm::normalize(((ptr->node->rotationMatrix() * vec) + ptr->node->worldPosition() - ptr->camera->positionVec3())); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - return glm::dvec2(backToScreenSpace.x / (2 * ptr->aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); - }; - FunctionData* ptr = reinterpret_cast(fdata); - glm::dvec3 surfacePoint = toSurface(x, ptr); // get current screen point from the id "x". + glm::dvec2 screenPoint; + if (x % 2) { // true = y[x] is a y-coord, false = y[x] is an x-coord + screenPoint.x = ptr->measurements[x - 1]; + screenPoint.y = ptr->measurements[x]; + } + else { + screenPoint.x = ptr->measurements[x]; + screenPoint.y = ptr->measurements[x + 1]; + } + glm::dvec3 surfacePoint = ptr->toSurface(screenPoint, ptr->camera, ptr->node, ptr->aspectRatio); // get current screen point from the id "x". // Create transformation matrix M(q) and apply transform for newPointInModelView glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); @@ -136,7 +113,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); // go back to screen-space if (x % 2) // return right variable return newScreenPoint.y; @@ -145,7 +122,12 @@ void TouchInteraction::update(const std::vector& list, std::vector

(fdata); + g[0] = 1.0; + g[1] = 1.0; + if (ptr->nDOF > 2) { + g[2] = 1.0; + // Get current screen point from the id "x". glm::dvec2 screenPoint; if (x % 2) { // true = y[x] is a y-coord, false = y[x] is an x-coord screenPoint.x = ptr->measurements[x - 1]; @@ -155,35 +137,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

measurements[x]; screenPoint.y = ptr->measurements[x + 1]; } - - // Find the intersection point in surface coordinates again; - glm::dvec3 camPos = ptr->camera->positionVec3(); - double xCo = 2 * (screenPoint.x - 0.5) * ptr->aspectRatio; - double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen - glm::dvec3 raytrace = glm::normalize(ptr->camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); - glm::dvec3 camToSelectable = ptr->node->worldPosition() - camPos; - double boundingSphere = ptr->node->boundingSphere(); - double d = glm::dot(raytrace, camToSelectable); - double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; - if (root > 0) // two intersection points (take the closest one) - d -= sqrt(root); - glm::dvec3 intersectionPoint = camPos + d * raytrace; - return (glm::inverse(ptr->node->rotationMatrix()) * (intersectionPoint - ptr->node->worldPosition())); - }; - auto toScreen = [](glm::dvec3 vec, FunctionData* ptr) { - glm::dvec3 backToScreenSpace = glm::inverse(ptr->camera->rotationQuaternion()) - * glm::normalize(((ptr->node->rotationMatrix() * vec) + ptr->node->worldPosition() - ptr->camera->positionVec3())); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - return glm::dvec2(backToScreenSpace.x / (2 * ptr->aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); - }; - - FunctionData* ptr = reinterpret_cast(fdata); - g[0] = 1.0; - g[1] = 1.0; - if (ptr->nDOF > 2) { - g[2] = 1.0; - // Get current screen point from the id "x". - glm::dvec3 surfacePoint = toSurface(x, ptr); + glm::dvec3 surfacePoint = ptr->toSurface(screenPoint, ptr->camera, ptr->node, ptr->aspectRatio); glm::dquat Q; Q.x = par[3]; @@ -201,7 +155,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(gradX, ptr->camera, ptr->node, ptr->aspectRatio);; if (x % 2) g[3] = newSPx.y; else @@ -218,8 +172,8 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(gradY, ptr->camera, ptr->node, ptr->aspectRatio);; + glm::dvec2 newSPz = ptr->toScreen(gradZ, ptr->camera, ptr->node, ptr->aspectRatio);; if (x % 2) { g[4] = newSPy.y; @@ -253,7 +207,29 @@ void TouchInteraction::update(const std::vector& list, std::vector

positionVec3(); + double xCo = 2 * (screenPoint.x - 0.5) * aspectRatio; + double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen + glm::dvec3 raytrace = glm::normalize(camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); + glm::dvec3 camToSelectable = node->worldPosition() - camPos; + double boundingSphere = node->boundingSphere(); + double d = glm::dot(raytrace, camToSelectable); + double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; + if (root > 0) // two intersection points (take the closest one) + d -= sqrt(root); + glm::dvec3 intersectionPoint = camPos + d * raytrace; + return (glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition())); + }; + auto toScreen = [](glm::dvec3 vec, Camera* camera, SceneGraphNode* node, double aspectRatio) { + glm::dvec3 backToScreenSpace = glm::inverse(camera->rotationQuaternion()) + * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera->positionVec3())); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + return glm::dvec2(backToScreenSpace.x / (2 * aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); + }; + + FunctionData fData = { _camera, _selected.at(0).node, res.x / res.y, screenPoints, nDOF, toScreen, toSurface }; void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); bool nIterations = levmarq(nDOF, par, nCoord, screenPoints, squaredError, func, grad, dataPtr, &_lmstat); // finds best transform values and stores them in par From 581f29ba95b128f7acc8d40544b6d52b86d920a1 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 14 Apr 2017 14:58:11 -0600 Subject: [PATCH 058/192] Using levmarq correctly now, need to double check if grad is the partial derivative of s(xi,q). Added name on credits --- CREDITS.md | 1 + modules/touch/ext/levmarq.cpp | 4 +- modules/touch/include/TouchInteraction.h | 9 +- modules/touch/src/TouchInteraction.cpp | 157 ++++++++--------------- 4 files changed, 60 insertions(+), 111 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 02aa209148..227160d04a 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -21,6 +21,7 @@ Rickard Lindtstedt Michael Sjöström Michael Novén Oskar Carlbaum +Jonathan Bosson Anteige noahdasanaike diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 365c2cacbd..50fb947047 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,7 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 1; + lmstat->verbose = 0; lmstat->max_it = 10000; lmstat->init_lambda = 0.0001; lmstat->up_factor = 10; @@ -155,7 +155,7 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, delete[] delta; delete[] newpar; - return (it+1); + return it; } diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index acd91b1e19..d6a49c689b 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -82,13 +82,12 @@ struct SelectedBody { }; struct FunctionData { + std::vector selectedPoints; + int nDOF; + glm::dvec2(*toScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); Camera* camera; SceneGraphNode* node; double aspectRatio; - double* measurements; - int nDOF; - glm::dvec2(*toScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); - glm::dvec3(*toSurface)(glm::dvec2, Camera*, SceneGraphNode*, double); }; using Point = std::pair; @@ -106,7 +105,7 @@ class TouchInteraction : public properties::PropertyOwner void step(double dt); void configSensitivities(double dist); void decelerate(); - glm::dvec2 modelToScreenSpace(SelectedBody sb); + glm::dvec2 modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node); void clear(); void tap(); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 4fec697cc6..e9dcd11af5 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -81,22 +81,11 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - if (_directTouchMode && _selected.size() > 0) { // should just be a function call - - // Returns the new value of screen point measurements[x] according to the transform M(par) - auto func = [](double* par, int x, void* fdata) { // par is the 6DOF vector , x the id of the measurements measurements[x], fdata additional data needed by the function + if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { // should just be a function call + // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi + auto func = [](double* par, int x, void* fdata) { FunctionData* ptr = reinterpret_cast(fdata); - glm::dvec2 screenPoint; - if (x % 2) { // true = y[x] is a y-coord, false = y[x] is an x-coord - screenPoint.x = ptr->measurements[x - 1]; - screenPoint.y = ptr->measurements[x]; - } - else { - screenPoint.x = ptr->measurements[x]; - screenPoint.y = ptr->measurements[x + 1]; - } - glm::dvec3 surfacePoint = ptr->toSurface(screenPoint, ptr->camera, ptr->node, ptr->aspectRatio); // get current screen point from the id "x". - + glm::dvec3 surfacePoint = ptr->selectedPoints.at(x / 2); // Create transformation matrix M(q) and apply transform for newPointInModelView glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); glm::dquat Q; @@ -112,7 +101,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); // go back to screen-space if (x % 2) // return right variable @@ -120,108 +108,67 @@ void TouchInteraction::update(const std::vector& list, std::vector

(fdata); - g[0] = 1.0; - g[1] = 1.0; + // Get current screen point from the id "x". + glm::dvec3 surfacePoint = ptr->selectedPoints.at(x / 2); + // s(xi,q) = toScreen(T + (Q * xi)) + // s'(xi,q) = + std::vector transform; + transform.push_back(ptr->toScreen(glm::dvec3(1.0, 0.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tx + transform.push_back(ptr->toScreen(glm::dvec3(0.0, 1.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Ty if (ptr->nDOF > 2) { - g[2] = 1.0; - // Get current screen point from the id "x". - glm::dvec2 screenPoint; - if (x % 2) { // true = y[x] is a y-coord, false = y[x] is an x-coord - screenPoint.x = ptr->measurements[x - 1]; - screenPoint.y = ptr->measurements[x]; - } - else { - screenPoint.x = ptr->measurements[x]; - screenPoint.y = ptr->measurements[x + 1]; - } - glm::dvec3 surfacePoint = ptr->toSurface(screenPoint, ptr->camera, ptr->node, ptr->aspectRatio); - + transform.push_back(ptr->toScreen(glm::dvec3(0.0, 0.0, 1.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tz glm::dquat Q; Q.x = par[3]; Q.y = Q.z = 0.0; + Q.w = sqrt(1.0 - Q.x*Q.x); + transform.push_back(ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rx if (ptr->nDOF > 4) { Q.y = par[4]; + Q.x = Q.z = 0.0; + Q.w = sqrt(1.0 - Q.y*Q.y); + transform.push_back(ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Ry + Q.z = par[5]; + Q.x = Q.y = 0.0; + Q.w = sqrt(1.0 - Q.z*Q.z); + transform.push_back(ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rz } - double len = Q.x*Q.x + Q.y*Q.y + Q.z*Q.z; - Q.w = sqrt(1 - len); + } - // We now got surface point, need to calculate Q' w.r.t x, y and z and calculate each gradient vector -> transform back to modelview to get g[3]-g[5] - glm::dvec3 gradX; // derivative of Q w.r.t x - gradX.x = surfacePoint.x - 2.0 * Q.y * surfacePoint.y + 2.0 * Q.z * surfacePoint.z; - gradX.y = 2.0 * Q.y * surfacePoint.x + (1.0 - 4.0 * Q.x) * surfacePoint.y + 2.0 * Q.w * surfacePoint.z; - gradX.z = 2.0 * Q.z * surfacePoint.x + 2.0 * Q.w * surfacePoint.y + 2.0 * (1.0 - 4.0 * Q.x) * surfacePoint.z; - - glm::dvec2 newSPx = ptr->toScreen(gradX, ptr->camera, ptr->node, ptr->aspectRatio);; + for (int i = 0; i < ptr->nDOF; ++i) { if (x % 2) - g[3] = newSPx.y; + g[i] = transform.at(i).y; else - g[3] = newSPx.x; - - if (ptr->nDOF > 4) { - glm::dvec3 gradY; // derivative of Q w.r.t y - gradY.x = (1.0 - 4.0 * Q.y) * surfacePoint.x + 2.0 * Q.x * surfacePoint.y + 2.0 * Q.w * surfacePoint.z; - gradY.y = 2.0 * Q.x * surfacePoint.x + surfacePoint.y + 2.0 * Q.z * surfacePoint.z; - gradY.z = -2.0 * Q.w * surfacePoint.x + 2.0 * Q.z * surfacePoint.y + (1.0 - 4.0 * Q.y) * surfacePoint.z; - - glm::dvec3 gradZ; // derivative of Q w.r.t z - gradZ.x = (1.0 - 4.0 * Q.z) * surfacePoint.x - 2.0 * Q.w * surfacePoint.y + 2.0 * Q.x * surfacePoint.z; - gradZ.y = 2.0 * Q.w * surfacePoint.x + (1.0 - 4.0 * Q.z) * surfacePoint.y + 2.0 * Q.y * surfacePoint.z; - gradZ.z = 2.0 * Q.x * surfacePoint.x + 2.0 * Q.y * surfacePoint.y + surfacePoint.z; - - glm::dvec2 newSPy = ptr->toScreen(gradY, ptr->camera, ptr->node, ptr->aspectRatio);; - glm::dvec2 newSPz = ptr->toScreen(gradZ, ptr->camera, ptr->node, ptr->aspectRatio);; - - if (x % 2) { - g[4] = newSPy.y; - g[5] = newSPz.y; - } - else { - g[4] = newSPy.x; - g[5] = newSPz.x; - } - } + g[i] = transform.at(i).x; } }; - const int nCoord = _selected.size() * 2; + SceneGraphNode* node = _selected.at(0).node; + const int nCoord = list.size() * 2; int nDOF = std::min(nCoord, 6); - double* par = new double[nDOF]; + double* par = new double[nDOF]; for (int i = 0; i < nDOF; ++i) // initial values of q or 0.0? (ie current model or no rotation/translation) par[i] = 0.0; + std::vector selectedPoints; + for (const SelectedBody& sb : _selected) { + selectedPoints.push_back(sb.coordinates); + } double* screenPoints = new double[nCoord]; double* squaredError = new double[nCoord]; int i = 0; - for (const SelectedBody& sb : _selected) { - glm::dvec2 screenPoint = modelToScreenSpace(sb); // transform to screen-space, old point to correct to current - screenPoints[i] = screenPoint.x; - screenPoints[i + 1] = screenPoint.y; + for (const TuioCursor& c : list) { + screenPoints[i] = c.getX(); + screenPoints[i + 1] = c.getY(); + + squaredError[i] = pow(c.getX() - modelToScreenSpace(selectedPoints.at(i/2), node).x, 2) ; + squaredError[i + 1] = pow(c.getY() - modelToScreenSpace(selectedPoints.at(i / 2), node).x, 2); - std::vector::const_iterator cursor = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return sb.id == c.getSessionID(); }); - squaredError[i] = pow(screenPoint.x - cursor->getX(), 2); // squared error to calculate weighted least-square - squaredError[i + 1] = pow(screenPoint.y - cursor->getY(), 2); i += 2; } - glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - - auto toSurface = [](glm::dvec2 screenPoint, Camera* camera, SceneGraphNode* node, double aspectRatio) { - // Find the intersection point in surface coordinates again; - glm::dvec3 camPos = camera->positionVec3(); - double xCo = 2 * (screenPoint.x - 0.5) * aspectRatio; - double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen - glm::dvec3 raytrace = glm::normalize(camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); - glm::dvec3 camToSelectable = node->worldPosition() - camPos; - double boundingSphere = node->boundingSphere(); - double d = glm::dot(raytrace, camToSelectable); - double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; - if (root > 0) // two intersection points (take the closest one) - d -= sqrt(root); - glm::dvec3 intersectionPoint = camPos + d * raytrace; - return (glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition())); - }; + auto toScreen = [](glm::dvec3 vec, Camera* camera, SceneGraphNode* node, double aspectRatio) { glm::dvec3 backToScreenSpace = glm::inverse(camera->rotationQuaternion()) * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera->positionVec3())); @@ -229,12 +176,14 @@ void TouchInteraction::update(const std::vector& list, std::vector

(&fData); - levmarq_init(&_lmstat); - bool nIterations = levmarq(nDOF, par, nCoord, screenPoints, squaredError, func, grad, dataPtr, &_lmstat); // finds best transform values and stores them in par - + levmarq_init(&_lmstat); + int nIterations = levmarq(nDOF, par, nCoord, screenPoints, NULL, func, grad, dataPtr, &_lmstat); // finds best transform values and stores them in par + + // debugging std::ostringstream os; for (int i = 0; i < nDOF; ++i) { os << par[i] << ", "; @@ -246,8 +195,8 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list) { } //debugging for (auto it : newSelected) { - std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; - //glm::dvec2 screenspace = modelToScreenSpace(it); + //std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; } _selected = newSelected; @@ -542,9 +490,9 @@ void TouchInteraction::step(double dt) { } -glm::dvec2 TouchInteraction::modelToScreenSpace(SelectedBody sb) { // returns a dvec2 of -1 to 1 ( top left is (0,0), bottom right is (1,1) ) +glm::dvec2 TouchInteraction::modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node) { // probably not needed, if squaredError isnt glm::dvec3 backToScreenSpace = glm::inverse(_camera->rotationQuaternion()) - * glm::normalize(((sb.node->rotationMatrix() * sb.coordinates) + sb.node->worldPosition() - _camera->positionVec3())); + * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - _camera->positionVec3())); backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); @@ -594,7 +542,8 @@ void TouchInteraction::clear() { _action.roll = false; _action.pick = false; - _selected.clear(); // should clear if no longer have a direct-touch input + //_directTouchMode = false; + //_selected.clear(); // should clear if no longer have a direct-touch input } void TouchInteraction::tap() { From 9c6ecdc6d3e2d9cad01ca0dbab621ef996af3212 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 14 Apr 2017 15:24:15 -0600 Subject: [PATCH 059/192] debugging camera transform for manipulation --- modules/touch/src/TouchInteraction.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index e9dcd11af5..5448bc3de5 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -99,7 +99,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); // go back to screen-space @@ -157,7 +157,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

& list, std::vector

rotate(Q); + _camera->setPositionVec3(_camera->positionVec3() + T); + // cleanup delete[] screenPoints; delete[] squaredError; @@ -198,7 +213,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition From 4c19391f63e3a764cdcc965bc027173d11952923 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 14 Apr 2017 17:00:46 -0600 Subject: [PATCH 060/192] found potential reasons for why par returns small values, might want to swap to rotate instead of trans on low DOF cases --- modules/touch/src/TouchInteraction.cpp | 40 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 5448bc3de5..7fee9e3e69 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -100,21 +100,21 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); // go back to screen-space - + if (x % 2) // return right variable return newScreenPoint.y; else return newScreenPoint.x; }; // Gradient of func w.r.t par - auto grad = [](double* g, double* par, int x, void* fdata) { + auto grad = [](double* g, double* par, int x, void* fdata) { // should g[i] = 1.0 or the derivative -> project to screen -> .x or .y? FunctionData* ptr = reinterpret_cast(fdata); - // Get current screen point from the id "x". glm::dvec3 surfacePoint = ptr->selectedPoints.at(x / 2); - // s(xi,q) = toScreen(T + (Q * xi)) - // s'(xi,q) = + + g[0] = 1.0; + g[1] = 1.0; std::vector transform; transform.push_back(ptr->toScreen(glm::dvec3(1.0, 0.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tx transform.push_back(ptr->toScreen(glm::dvec3(0.0, 1.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Ty @@ -125,6 +125,9 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rx + + g[2] = 1.0; + g[3] = 1.0; if (ptr->nDOF > 4) { Q.y = par[4]; Q.x = Q.z = 0.0; @@ -135,21 +138,25 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rz + + g[4] = 1.0; + g[5] = 1.0; } } - for (int i = 0; i < ptr->nDOF; ++i) { + /*for (int i = 0; i < ptr->nDOF; ++i) { if (x % 2) g[i] = transform.at(i).y; else g[i] = transform.at(i).x; - } + }*/ }; SceneGraphNode* node = _selected.at(0).node; const int nCoord = list.size() * 2; int nDOF = std::min(nCoord, 6); double* par = new double[nDOF]; + double tPar[6] = { node->worldPosition().x, node->worldPosition().y, node->worldPosition().z, 0.0, 0.0, 0.0 }; for (int i = 0; i < nDOF; ++i) // initial values of q or 0.0? (ie current model or no rotation/translation) par[i] = 0.0; std::vector selectedPoints; @@ -187,8 +194,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

rotate(Q); - _camera->setPositionVec3(_camera->positionVec3() + T); + + + /* Things to test - potential reasons why values are so small + * initial values on par + * redefine grad to be partial derivative (mostly par[3]-par[5]) + * change to add rotation on par[0]-par[2] instead + * change lmstat init + + */ + _camera->setPositionVec3(_camera->positionVec3() - T); + _camera->rotate(glm::inverse(Q)); // cleanup delete[] screenPoints; From 58796ca39074379eec0f54a51f03e2865caf1e72 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 18 Apr 2017 15:57:07 -0600 Subject: [PATCH 061/192] func in levmarq now handles the distance between two screen points (one projected from the spheres surface), need to define gradient correctly --- modules/touch/ext/levmarq.cpp | 39 ++++++---- modules/touch/ext/levmarq.h | 4 +- modules/touch/include/TouchInteraction.h | 1 + modules/touch/src/TouchInteraction.cpp | 96 ++++++++++-------------- 4 files changed, 67 insertions(+), 73 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 50fb947047..8482ef4b2b 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,8 +30,8 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 0; - lmstat->max_it = 10000; + lmstat->verbose = 1; + lmstat->max_it = 20; lmstat->init_lambda = 0.0001; lmstat->up_factor = 10; lmstat->down_factor = 10; @@ -57,7 +57,7 @@ The arguments are as follows: Before calling levmarq, several of the parameters in lmstat must be set. For default values, call levmarq_init(lmstat). */ -int levmarq(int npar, double *par, int ny, double *y, double *dysq, +int levmarq(int npar, double *par, int ny, double *dysq, double (*func)(double *, int, void *), void (*grad)(double *, double *, int, void *), void *fdata, LMstat *lmstat) { @@ -87,7 +87,7 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, derr = newerr = 0; // to avoid compiler warnings // calculate the initial error ("chi-squared") - err = error_func(par, ny, y, dysq, func, fdata); + err = error_func(par, ny, dysq, func, fdata); // main iteration for (it = 0; it < nit; it++) { @@ -102,7 +102,7 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, weight = 1/dysq[x]; // for weighted least-squares grad(g, par, x, fdata); for (i = 0; i < npar; i++) { - d[i] += (y[x] - func(par, x, fdata)) * g[i] * weight; + d[i] += func(par, x, fdata) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight; for (j = 0; j <= i; j++) h[i][j] += g[i] * g[j] * weight; } @@ -110,20 +110,29 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, // make a step "delta." If the step is rejected, increase lambda and try again mult = 1 + lambda; ill = 1; // ill-conditioned? - while (ill && (it 0); } - if (verbose) + if (verbose) { printf("it = %4d, lambda = %10g, err = %10g, derr = %10g\n", it, lambda, err, derr); + for (i = 0; i < npar; i++) { + printf("%f:", par[i]); + } + printf("\n"); + for (i = 0; i < npar; ++i) { + printf("%f:", delta[i]); + } + printf("\n"); + } if (ill) { mult = (1 + lambda * up) / (1 + lambda); lambda *= up; @@ -133,9 +142,9 @@ int levmarq(int npar, double *par, int ny, double *y, double *dysq, for (i = 0; i < npar; i++) par[i] = newpar[i]; err = newerr; - lambda *= down; + lambda *= down; - if ((!ill) && (-derr= 0; i--) { diff --git a/modules/touch/ext/levmarq.h b/modules/touch/ext/levmarq.h index 3b5117edd7..610cefa3ff 100644 --- a/modules/touch/ext/levmarq.h +++ b/modules/touch/ext/levmarq.h @@ -38,12 +38,12 @@ typedef struct { void levmarq_init(LMstat *lmstat); -int levmarq(int npar, double *par, int ny, double *y, double *dysq, +int levmarq(int npar, double *par, int ny, double *dysq, double (*func)(double *, int, void *), void (*grad)(double *, double *, int, void *), void *fdata, LMstat *lmstat); -double error_func(double *par, int ny, double *y, double *dysq, +double error_func(double *par, int ny, double *dysq, double (*func)(double *, int, void *), void *fdata); void solve_axb_cholesky(int n, double** l, double* x, double* b); diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index d6a49c689b..b1f9a0b39c 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -83,6 +83,7 @@ struct SelectedBody { struct FunctionData { std::vector selectedPoints; + std::vector screenPoints; int nDOF; glm::dvec2(*toScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); Camera* camera; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 7fee9e3e69..11afe8435c 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -83,9 +83,10 @@ TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { // should just be a function call // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi - auto func = [](double* par, int x, void* fdata) { + auto distToMinimize = [](double* par, int x, void* fdata) { FunctionData* ptr = reinterpret_cast(fdata); - glm::dvec3 surfacePoint = ptr->selectedPoints.at(x / 2); + glm::dvec3 surfacePoint = ptr->selectedPoints.at(x); + // Create transformation matrix M(q) and apply transform for newPointInModelView glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); glm::dquat Q; @@ -100,80 +101,64 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); // go back to screen-space - - if (x % 2) // return right variable - return newScreenPoint.y; - else - return newScreenPoint.x; - }; - // Gradient of func w.r.t par - auto grad = [](double* g, double* par, int x, void* fdata) { // should g[i] = 1.0 or the derivative -> project to screen -> .x or .y? - FunctionData* ptr = reinterpret_cast(fdata); - glm::dvec3 surfacePoint = ptr->selectedPoints.at(x / 2); - g[0] = 1.0; - g[1] = 1.0; - std::vector transform; - transform.push_back(ptr->toScreen(glm::dvec3(1.0, 0.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tx - transform.push_back(ptr->toScreen(glm::dvec3(0.0, 1.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Ty + return glm::length(ptr->screenPoints.at(x) - newScreenPoint); + }; + // Gradient of distToMinimize w.r.t par + auto gradient = [](double* g, double* par, int x, void* fdata) { // should g[i] = 1.0 or the derivative -> project to screen -> .x or .y? + FunctionData* ptr = reinterpret_cast(fdata); + glm::dvec3 surfacePoint = ptr->selectedPoints.at(x); + g[0] = glm::length(-ptr->toScreen(glm::dvec3(1.0, 0.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tx + //g[0] = 1.0; + g[1] = glm::length(-ptr->toScreen(glm::dvec3(0.0, 1.0 , 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Ty + //g[1] = 1.0; if (ptr->nDOF > 2) { - transform.push_back(ptr->toScreen(glm::dvec3(0.0, 0.0, 1.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tz + g[2] = glm::length(-ptr->toScreen(glm::dvec3(0.0, 0.0, 1.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tz + //g[2] = 1.0; glm::dquat Q; - Q.x = par[3]; + Q.x = 1.0; Q.y = Q.z = 0.0; Q.w = sqrt(1.0 - Q.x*Q.x); - transform.push_back(ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rx - - g[2] = 1.0; - g[3] = 1.0; + g[3] = glm::length(-ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rx + //g[3] = 1.0; if (ptr->nDOF > 4) { - Q.y = par[4]; + Q.y = 1.0; Q.x = Q.z = 0.0; Q.w = sqrt(1.0 - Q.y*Q.y); - transform.push_back(ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Ry + g[4] = glm::length(-ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Ry + //g[4] = 1.0; - Q.z = par[5]; + Q.z = 1.0; Q.x = Q.y = 0.0; Q.w = sqrt(1.0 - Q.z*Q.z); - transform.push_back(ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rz - - g[4] = 1.0; - g[5] = 1.0; + g[5] = glm::length(-ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rz + //g[5] = 1.0; } } - /*for (int i = 0; i < ptr->nDOF; ++i) { - if (x % 2) - g[i] = transform.at(i).y; - else - g[i] = transform.at(i).x; - }*/ }; SceneGraphNode* node = _selected.at(0).node; - const int nCoord = list.size() * 2; - int nDOF = std::min(nCoord, 6); + const int nFingers = list.size(); + int nDOF = std::min(static_cast(list.size() * 2), 6); double* par = new double[nDOF]; double tPar[6] = { node->worldPosition().x, node->worldPosition().y, node->worldPosition().z, 0.0, 0.0, 0.0 }; for (int i = 0; i < nDOF; ++i) // initial values of q or 0.0? (ie current model or no rotation/translation) par[i] = 0.0; std::vector selectedPoints; + std::vector screenPoints; for (const SelectedBody& sb : _selected) { selectedPoints.push_back(sb.coordinates); + + std::vector::const_iterator c = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return c.getSessionID() == sb.id; }); + screenPoints.push_back(glm::dvec2(c->getX(), c->getY())); } - double* screenPoints = new double[nCoord]; - double* squaredError = new double[nCoord]; // probably not be needed - int i = 0; - for (const TuioCursor& c : list) { - screenPoints[i] = c.getX(); - screenPoints[i + 1] = c.getY(); - - squaredError[i] = pow(c.getX() - modelToScreenSpace(selectedPoints.at(i/2), node).x, 2) ; - squaredError[i + 1] = pow(c.getY() - modelToScreenSpace(selectedPoints.at(i / 2), node).x, 2); - - i += 2; + double* squaredError = new double[nFingers]; // probably not needed + for (int i = 0; i < nFingers; ++i) { + double err = glm::length(screenPoints.at(i) - modelToScreenSpace(selectedPoints.at(i), node)); + squaredError[i] = err*err; } auto toScreen = [](glm::dvec3 vec, Camera* camera, SceneGraphNode* node, double aspectRatio) { @@ -184,11 +169,11 @@ void TouchInteraction::update(const std::vector& list, std::vector

(&fData); levmarq_init(&_lmstat); - int nIterations = levmarq(nDOF, par, nCoord, screenPoints, NULL, func, grad, dataPtr, &_lmstat); // finds best transform values and stores them in par + int nIterations = levmarq(nDOF, par, list.size(), NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par double temp[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; for (int i = 0; i < nDOF; ++i) @@ -205,7 +190,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

setPositionVec3(_camera->positionVec3() - T); - _camera->rotate(glm::inverse(Q)); + //_camera->setPositionVec3(_camera->positionVec3() - T); + //_camera->rotate(glm::inverse(Q)); // cleanup - delete[] screenPoints; delete[] squaredError; delete[] par; } From 0e1b39945857a2166ceb1e6554564353a116be49 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 18 Apr 2017 16:52:16 -0600 Subject: [PATCH 062/192] instead of projecting to screen-space the error is now calculated in modelspace (tracing current viewplane pos to surface coordinates) --- modules/touch/ext/levmarq.cpp | 6 +- modules/touch/include/TouchInteraction.h | 2 +- modules/touch/src/TouchInteraction.cpp | 72 +++++++++++------------- 3 files changed, 36 insertions(+), 44 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 8482ef4b2b..b86aa1ca79 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,8 +30,8 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 1; - lmstat->max_it = 20; + lmstat->verbose = 0; + lmstat->max_it = 1000; lmstat->init_lambda = 0.0001; lmstat->up_factor = 10; lmstat->down_factor = 10; @@ -123,7 +123,7 @@ int levmarq(int npar, double *par, int ny, double *dysq, ill = (derr > 0); } if (verbose) { - printf("it = %4d, lambda = %10g, err = %10g, derr = %10g\n", it, lambda, err, derr); + printf("it = %4d, lambda = %10g, err = %10g, derr = %10g\n", it, newerr, err, derr); for (i = 0; i < npar; i++) { printf("%f:", par[i]); } diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index b1f9a0b39c..be1b17a70f 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -85,7 +85,7 @@ struct FunctionData { std::vector selectedPoints; std::vector screenPoints; int nDOF; - glm::dvec2(*toScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); + glm::dvec3(*toSurface)(glm::dvec2, Camera*, SceneGraphNode*, double); Camera* camera; SceneGraphNode* node; double aspectRatio; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 11afe8435c..bebd6cf723 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -85,7 +85,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

(fdata); - glm::dvec3 surfacePoint = ptr->selectedPoints.at(x); + glm::dvec3 selectedPoint = ptr->selectedPoints.at(x); // Create transformation matrix M(q) and apply transform for newPointInModelView glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); @@ -101,40 +101,31 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); // go back to screen-space + glm::dvec3 newSurfacePoint = (Q * selectedPoint) + T; + glm::dvec3 currentSurfacePoint = ptr->toSurface(ptr->screenPoints.at(x), ptr->camera, ptr->node, ptr->aspectRatio); - return glm::length(ptr->screenPoints.at(x) - newScreenPoint); + return glm::length(currentSurfacePoint - newSurfacePoint); }; // Gradient of distToMinimize w.r.t par auto gradient = [](double* g, double* par, int x, void* fdata) { // should g[i] = 1.0 or the derivative -> project to screen -> .x or .y? FunctionData* ptr = reinterpret_cast(fdata); glm::dvec3 surfacePoint = ptr->selectedPoints.at(x); - g[0] = glm::length(-ptr->toScreen(glm::dvec3(1.0, 0.0, 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tx - //g[0] = 1.0; - g[1] = glm::length(-ptr->toScreen(glm::dvec3(0.0, 1.0 , 0.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Ty - //g[1] = 1.0; + g[0] = -1.0; // Tx + g[1] = -1.0; // Ty if (ptr->nDOF > 2) { - g[2] = glm::length(-ptr->toScreen(glm::dvec3(0.0, 0.0, 1.0), ptr->camera, ptr->node, ptr->aspectRatio)); // Tz - //g[2] = 1.0; + g[2] = -1.0; // Tz glm::dquat Q; Q.x = 1.0; - Q.y = Q.z = 0.0; - Q.w = sqrt(1.0 - Q.x*Q.x); - g[3] = glm::length(-ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rx - //g[3] = 1.0; + Q.y = Q.z = Q.w = 0.0; + g[3] = -glm::length(Q * surfacePoint); // Rx if (ptr->nDOF > 4) { Q.y = 1.0; - Q.x = Q.z = 0.0; - Q.w = sqrt(1.0 - Q.y*Q.y); - g[4] = glm::length(-ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Ry - //g[4] = 1.0; + Q.x = Q.z = Q.w = 0.0; + g[4] = -glm::length(Q * surfacePoint); // Rx Q.z = 1.0; - Q.x = Q.y = 0.0; - Q.w = sqrt(1.0 - Q.z*Q.z); - g[5] = glm::length(-ptr->toScreen(Q * surfacePoint, ptr->camera, ptr->node, ptr->aspectRatio)); // Rz - //g[5] = 1.0; + Q.x = Q.y = Q.w = 0.0; + g[5] = -glm::length(Q * surfacePoint); // Rx } } @@ -161,19 +152,29 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationQuaternion()) - * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera->positionVec3())); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - return glm::dvec2(backToScreenSpace.x / (2 * aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); + + auto toSurface = [](glm::dvec2 screenPoint, Camera* camera, SceneGraphNode* node, double aspectRatio) { + // Find the intersection point in surface coordinates again; + glm::dvec3 camPos = camera->positionVec3(); + double xCo = 2 * (screenPoint.x - 0.5) * aspectRatio; + double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen + glm::dvec3 raytrace = glm::normalize(camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); + glm::dvec3 camToSelectable = node->worldPosition() - camPos; + double boundingSphere = node->boundingSphere(); + double d = glm::dot(raytrace, camToSelectable); + double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; + if (root > 0) // two intersection points (take the closest one) + d -= sqrt(root); + glm::dvec3 intersectionPoint = camPos + d * raytrace; + return (glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition())); }; glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, toScreen, _camera, node, res.x / res.y}; + FunctionData fData = { selectedPoints, screenPoints, nDOF, toSurface, _camera, node, res.x / res.y}; void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); - int nIterations = levmarq(nDOF, par, list.size(), NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par + int nIterations = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par double temp[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; for (int i = 0; i < nDOF; ++i) @@ -192,17 +193,8 @@ void TouchInteraction::update(const std::vector& list, std::vector

setPositionVec3(_camera->positionVec3() - T); - //_camera->rotate(glm::inverse(Q)); + _camera->setPositionVec3(_camera->positionVec3() - T); + _camera->rotate(glm::inverse(Q)); // cleanup delete[] squaredError; From 099c3436932bf425a00c8b07ad1beb44f1489a47 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 19 Apr 2017 18:14:47 -0600 Subject: [PATCH 063/192] levmarq using correct gradient (finite derivative) and using the error to determine next delta step --- ext/ghoul | 2 +- modules/touch/ext/levmarq.cpp | 12 ++--- modules/touch/ext/levmarq.h | 2 +- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 57 ++++++++++++------------ modules/touch/touchmodule.cpp | 2 +- 6 files changed, 40 insertions(+), 38 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 200401261c..c37ff8beb5 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 200401261cba513fb1faa4b7e92bd213435625ad +Subproject commit c37ff8beb5b8825ecb67b121ae4deac34677e1bd diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index b86aa1ca79..b3c472f89c 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,9 +30,9 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 0; - lmstat->max_it = 1000; - lmstat->init_lambda = 0.0001; + lmstat->verbose = 1; + lmstat->max_it = 5000; + lmstat->init_lambda = 1e-6; lmstat->up_factor = 10; lmstat->down_factor = 10; lmstat->target_derr = 1e-12; @@ -57,7 +57,7 @@ The arguments are as follows: Before calling levmarq, several of the parameters in lmstat must be set. For default values, call levmarq_init(lmstat). */ -int levmarq(int npar, double *par, int ny, double *dysq, +int levmarq(int npar, double *par, int ny, double* y, double *dysq, double (*func)(double *, int, void *), void (*grad)(double *, double *, int, void *), void *fdata, LMstat *lmstat) { @@ -102,7 +102,7 @@ int levmarq(int npar, double *par, int ny, double *dysq, weight = 1/dysq[x]; // for weighted least-squares grad(g, par, x, fdata); for (i = 0; i < npar; i++) { - d[i] += func(par, x, fdata) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight; + d[i] += (y[i] - func(par, x, fdata)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight; for (j = 0; j <= i; j++) h[i][j] += g[i] * g[j] * weight; } @@ -123,7 +123,7 @@ int levmarq(int npar, double *par, int ny, double *dysq, ill = (derr > 0); } if (verbose) { - printf("it = %4d, lambda = %10g, err = %10g, derr = %10g\n", it, newerr, err, derr); + printf("it = %4d, newerror = %10g, err = %10g, derr = %10g\n", it, newerr, err, derr); for (i = 0; i < npar; i++) { printf("%f:", par[i]); } diff --git a/modules/touch/ext/levmarq.h b/modules/touch/ext/levmarq.h index 610cefa3ff..4dad30e0a1 100644 --- a/modules/touch/ext/levmarq.h +++ b/modules/touch/ext/levmarq.h @@ -38,7 +38,7 @@ typedef struct { void levmarq_init(LMstat *lmstat); -int levmarq(int npar, double *par, int ny, double *dysq, +int levmarq(int npar, double *par, int ny, double* y, double *dysq, double (*func)(double *, int, void *), void (*grad)(double *, double *, int, void *), void *fdata, LMstat *lmstat); diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index be1b17a70f..697c5e25e7 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -85,7 +85,8 @@ struct FunctionData { std::vector selectedPoints; std::vector screenPoints; int nDOF; - glm::dvec3(*toSurface)(glm::dvec2, Camera*, SceneGraphNode*, double); + glm::dvec2(*toScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); + double(*distToMinimize)(double* par, int x, void* fdata); Camera* camera; SceneGraphNode* node; double aspectRatio; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index bebd6cf723..f328aa0305 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -90,7 +90,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

nDOF > 2) { // need to check how many DOF we can handle (+2 DOF per finger down up to 6) T.z = par[2]; Q.x = par[3]; @@ -99,36 +99,30 @@ void TouchInteraction::update(const std::vector& list, std::vector

toSurface(ptr->screenPoints.at(x), ptr->camera, ptr->node, ptr->aspectRatio); + glm::dvec2 newScreenPoint = ptr->toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); - return glm::length(currentSurfacePoint - newSurfacePoint); + return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; - // Gradient of distToMinimize w.r.t par + // Gradient (finite derivative) of distToMinimize w.r.t par auto gradient = [](double* g, double* par, int x, void* fdata) { // should g[i] = 1.0 or the derivative -> project to screen -> .x or .y? FunctionData* ptr = reinterpret_cast(fdata); - glm::dvec3 surfacePoint = ptr->selectedPoints.at(x); - g[0] = -1.0; // Tx - g[1] = -1.0; // Ty - if (ptr->nDOF > 2) { - g[2] = -1.0; // Tz - glm::dquat Q; - Q.x = 1.0; - Q.y = Q.z = Q.w = 0.0; - g[3] = -glm::length(Q * surfacePoint); // Rx - if (ptr->nDOF > 4) { - Q.y = 1.0; - Q.x = Q.z = Q.w = 0.0; - g[4] = -glm::length(Q * surfacePoint); // Rx + double f0 = ptr->distToMinimize(par, x, fdata); + double f1, h = 1e-4; + double* dPar = new double[ptr->nDOF]; - Q.z = 1.0; - Q.x = Q.y = Q.w = 0.0; - g[5] = -glm::length(Q * surfacePoint); // Rx + for (int i = 0; i < ptr->nDOF; ++i) { + for (int j = 0; j < ptr->nDOF; ++j) { + dPar[j] = par[j]; } - } + dPar[i] += h; + f1 = ptr->distToMinimize(dPar, x, fdata); + g[i] = (f1 - f0) / h; + } + delete[] dPar; }; SceneGraphNode* node = _selected.at(0).node; @@ -149,7 +143,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

rotationMatrix()) * (intersectionPoint - node->worldPosition())); }; + auto toScreen = [](glm::dvec3 vec, Camera* camera, SceneGraphNode* node, double aspectRatio) { + glm::dvec3 backToScreenSpace = glm::inverse(camera->rotationQuaternion()) + * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera->positionVec3())); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + return glm::dvec2(backToScreenSpace.x / (2 * aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); + }; + glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, toSurface, _camera, node, res.x / res.y}; + FunctionData fData = { selectedPoints, screenPoints, nDOF, toScreen, distToMinimize, _camera, node, res.x / res.y}; void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); - int nIterations = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par + int nIterations = levmarq(nDOF, par, nFingers, squaredError, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par double temp[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; for (int i = 0; i < nDOF; ++i) @@ -194,7 +195,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

setPositionVec3(_camera->positionVec3() - T); - _camera->rotate(glm::inverse(Q)); + //_camera->rotate(glm::inverse(Q)); // cleanup delete[] squaredError; @@ -548,7 +549,7 @@ void TouchInteraction::clear() { _action.pick = false; //_directTouchMode = false; - //_selected.clear(); // should clear if no longer have a direct-touch input + _selected.clear(); // should clear if no longer have a direct-touch input } void TouchInteraction::tap() { diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 0a6bbba6de..243084d9df 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -156,7 +156,7 @@ TouchModule::TouchModule() os.clear(); } - else + else if (list.size() == 0) touch->clear(); // update lastProcessed From 0542e7cef57dfb3f7a07a765fcbf98086541effb Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 20 Apr 2017 15:22:53 -0600 Subject: [PATCH 064/192] Levmarq gives right q values, need to transform them to camera space correctly --- ext/ghoul | 2 +- modules/touch/ext/levmarq.cpp | 4 +-- modules/touch/src/TouchInteraction.cpp | 50 ++++++++++++-------------- openspace.cfg | 2 +- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index c37ff8beb5..200401261c 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit c37ff8beb5b8825ecb67b121ae4deac34677e1bd +Subproject commit 200401261cba513fb1faa4b7e92bd213435625ad diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index b3c472f89c..6f690930dc 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,7 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 1; + lmstat->verbose = 0; lmstat->max_it = 5000; lmstat->init_lambda = 1e-6; lmstat->up_factor = 10; @@ -102,7 +102,7 @@ int levmarq(int npar, double *par, int ny, double* y, double *dysq, weight = 1/dysq[x]; // for weighted least-squares grad(g, par, x, fdata); for (i = 0; i < npar; i++) { - d[i] += (y[i] - func(par, x, fdata)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight; + d[i] += (0.0 - func(par, x, fdata)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight; for (j = 0; j <= i; j++) h[i][j] += g[i] * g[j] * weight; } diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index f328aa0305..cd4f91a188 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -101,7 +101,11 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); return glm::length(ptr->screenPoints.at(x) - newScreenPoint); @@ -127,7 +131,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

(list.size() * 2), 6); + int nDOF = std::min(nFingers * 2, 6); double* par = new double[nDOF]; double tPar[6] = { node->worldPosition().x, node->worldPosition().y, node->worldPosition().z, 0.0, 0.0, 0.0 }; for (int i = 0; i < nDOF; ++i) // initial values of q or 0.0? (ie current model or no rotation/translation) @@ -146,23 +150,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

positionVec3(); - double xCo = 2 * (screenPoint.x - 0.5) * aspectRatio; - double yCo = -2 * (screenPoint.y - 0.5); // normalized -1 to 1 coordinates on screen - glm::dvec3 raytrace = glm::normalize(camera->rotationQuaternion() * glm::dvec3(xCo, yCo, -3.2596558)); - glm::dvec3 camToSelectable = node->worldPosition() - camPos; - double boundingSphere = node->boundingSphere(); - double d = glm::dot(raytrace, camToSelectable); - double root = boundingSphere * boundingSphere - glm::dot(camToSelectable, camToSelectable) + d * d; - if (root > 0) // two intersection points (take the closest one) - d -= sqrt(root); - glm::dvec3 intersectionPoint = camPos + d * raytrace; - return (glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition())); - }; - auto toScreen = [](glm::dvec3 vec, Camera* camera, SceneGraphNode* node, double aspectRatio) { glm::dvec3 backToScreenSpace = glm::inverse(camera->rotationQuaternion()) * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera->positionVec3())); @@ -171,7 +158,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

(&fData); levmarq_init(&_lmstat); @@ -187,15 +174,22 @@ void TouchInteraction::update(const std::vector& list, std::vector

setPositionVec3(_camera->positionVec3() - T); - //_camera->rotate(glm::inverse(Q)); + glm::dmat4 rot = glm::toMat4(Q); + glm::dmat4 trans = glm::translate(glm::dmat4(1.0f), T); + glm::dmat4 finalTransform = (static_cast(node->rotationMatrix()) * (rot * trans)); + + + // newWorldPoint = node->rotationMatrix() * ((M(q) * selectedPoint)) (+ node->worldPosition()) + + glm::dquat camQ = glm::inverse(Q); + glm::dvec3 camT = glm::dvec3(finalTransform[3][0], finalTransform[3][1], finalTransform[3][2]); //node->rotationMatrix() * T; + + //_camera->rotate(camQ); + _camera->setPositionVec3(_camera->positionVec3() - camT); + + // debugging + std::cout << "Levmarq success after " << nIterations << " iterations. Camera T: " << glm::to_string(camT) << ", Q: " << glm::to_string(camQ) << ", " << glm::to_string(finalTransform) << "\n"; // cleanup delete[] squaredError; diff --git a/openspace.cfg b/openspace.cfg index c4626ffadb..ceceb5af30 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -26,7 +26,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/default.scene", + Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", From c129bf1112451e7352a30048c26188f33b7bf9f1 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 20 Apr 2017 17:02:19 -0600 Subject: [PATCH 065/192] find minimum vector q that applies to the transform in camera space --- modules/touch/include/TouchInteraction.h | 2 +- modules/touch/src/TouchInteraction.cpp | 48 ++++++++++++------------ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 697c5e25e7..a0fabee023 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -85,7 +85,7 @@ struct FunctionData { std::vector selectedPoints; std::vector screenPoints; int nDOF; - glm::dvec2(*toScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); + glm::dvec2(*castToScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); double(*distToMinimize)(double* par, int x, void* fdata); Camera* camera; SceneGraphNode* node; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index cd4f91a188..b6eeb366b1 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -101,13 +101,16 @@ void TouchInteraction::update(const std::vector& list, std::vector

toScreen(newSurfacePoint, ptr->camera, ptr->node, ptr->aspectRatio); + glm::dvec3 pointInCamSpace = glm::inverse(ptr->camera->rotationQuaternion()) * (ptr->node->rotationMatrix() * selectedPoint); + glm::dvec3 newWorldSP = Q * (pointInCamSpace + T); // cam space around origin + //glm::dvec3 newWorldSP = transform * glm::dvec4(pointInCamSpace, 1.0); // cam space around origin + + glm::dvec2 newScreenPoint = ptr->castToScreen(newWorldSP, ptr->camera, ptr->node, ptr->aspectRatio); return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; // Gradient (finite derivative) of distToMinimize w.r.t par @@ -150,15 +153,18 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationQuaternion()) - * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera->positionVec3())); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - return glm::dvec2(backToScreenSpace.x / (2 * aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); + auto castToScreen = [](glm::dvec3 camVec, Camera* camera, SceneGraphNode* node, double aspectRatio) { + glm::dvec3 vecInWorldSpace = camera->rotationQuaternion() * camVec; + glm::dvec3 rayFromCamToPoint = glm::normalize(vecInWorldSpace + node->worldPosition() - camera->positionVec3()); + + glm::dvec3 pointInNDC = glm::inverse(camera->rotationQuaternion()) * rayFromCamToPoint; + pointInNDC *= (-3.2596558 / pointInNDC.z); + + return glm::dvec2(pointInNDC.x / (2 * aspectRatio) + 0.5, -pointInNDC.y / 2 + 0.5); // returns [0,0] - [1,1] point }; glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, toScreen, distToMinimize, _camera, node, res.x / res.y }; + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToScreen, distToMinimize, _camera, node, res.x / res.y }; void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); @@ -174,22 +180,18 @@ void TouchInteraction::update(const std::vector& list, std::vector

(node->rotationMatrix()) * (rot * trans)); + glm::dquat worldQ = Q; + glm::dvec3 worldT = _camera->rotationQuaternion() * T; // glm::dvec3(transform[3][0], transform[3][1], transform[3][2]); - - // newWorldPoint = node->rotationMatrix() * ((M(q) * selectedPoint)) (+ node->worldPosition()) - - glm::dquat camQ = glm::inverse(Q); - glm::dvec3 camT = glm::dvec3(finalTransform[3][0], finalTransform[3][1], finalTransform[3][2]); //node->rotationMatrix() * T; - - //_camera->rotate(camQ); - _camera->setPositionVec3(_camera->positionVec3() - camT); + _camera->rotate(worldQ); + _camera->setPositionVec3(_camera->positionVec3() - worldT); // debugging - std::cout << "Levmarq success after " << nIterations << " iterations. Camera T: " << glm::to_string(camT) << ", Q: " << glm::to_string(camQ) << ", " << glm::to_string(finalTransform) << "\n"; + std::cout << "Levmarq success after " << nIterations << " iterations. Camera T: " << glm::to_string(worldT) << ", Q: " << glm::to_string(Q) << "\n"; // cleanup delete[] squaredError; From c54039225d8a570d584fdb0591a4b7652a3d5560 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 21 Apr 2017 13:20:02 -0600 Subject: [PATCH 066/192] Rotation now uses euler angles and modulus to make use of camera rotational axis, 4th DOF is set to be roll --- modules/touch/src/TouchInteraction.cpp | 37 +++++++++++--------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index b6eeb366b1..06faafbfa3 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -44,6 +44,7 @@ #endif #include +#include #include namespace { @@ -86,30 +87,25 @@ void TouchInteraction::update(const std::vector& list, std::vector

(fdata); glm::dvec3 selectedPoint = ptr->selectedPoints.at(x); + glm::dvec3 pointInCamSpace = glm::inverse(ptr->camera->rotationQuaternion()) * (ptr->node->rotationMatrix() * selectedPoint); // Create transformation matrix M(q) and apply transform for newPointInModelView glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); - glm::dquat Q; - Q.x = Q.y = Q.z = Q.w = 0.0; + glm::dvec3 eulerAngles(0.0, 0.0, 0.0); + double twoPi = 2.0 * M_PI; if (ptr->nDOF > 2) { // need to check how many DOF we can handle (+2 DOF per finger down up to 6) T.z = par[2]; - Q.x = par[3]; + eulerAngles.z = fmod(par[3], twoPi); if (ptr->nDOF > 4) { - Q.y = par[4]; - Q.z = par[5]; + eulerAngles.y = fmod(par[4], twoPi); + eulerAngles.x = fmod(par[5], twoPi); } } - Q.w = sqrt(1.0 - std::min(glm::length(Q), 0.99999)); // if check is not done Q.w becomes NAN. Do we need a better definition of Q.w? + glm::dquat Q = glm::normalize(glm::dquat(eulerAngles)); - /*glm::dmat4 rotate = glm::toMat4(Q); - glm::dmat4 translate = glm::translate(glm::dmat4(1.0f), T); - glm::dmat4 transform = rotate * translate;*/ - - glm::dvec3 pointInCamSpace = glm::inverse(ptr->camera->rotationQuaternion()) * (ptr->node->rotationMatrix() * selectedPoint); - glm::dvec3 newWorldSP = Q * (pointInCamSpace + T); // cam space around origin + glm::dvec3 newWorldSP = (Q * pointInCamSpace) + T; // cam space around origin //glm::dvec3 newWorldSP = transform * glm::dvec4(pointInCamSpace, 1.0); // cam space around origin - glm::dvec2 newScreenPoint = ptr->castToScreen(newWorldSP, ptr->camera, ptr->node, ptr->aspectRatio); return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; @@ -175,23 +171,22 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationQuaternion() * T; // glm::dvec3(transform[3][0], transform[3][1], transform[3][2]); - - _camera->rotate(worldQ); + _camera->setPositionVec3(_camera->positionVec3() - worldT); + _camera->rotate(worldQ); + // debugging - std::cout << "Levmarq success after " << nIterations << " iterations. Camera T: " << glm::to_string(worldT) << ", Q: " << glm::to_string(Q) << "\n"; + std::cout << "Levmarq success after " << nIterations << " iterations. Camera T: " << glm::to_string(worldT) << ", Q: " << glm::to_string(worldQ) << "\n"; // cleanup delete[] squaredError; From 3157ac437895201a8404b5133187bd22518b2783 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 21 Apr 2017 16:35:56 -0600 Subject: [PATCH 067/192] minimization method now finds best-fit values that manipulates the camera state such a way that the error in screen-space is < epsilon --- modules/touch/include/TouchInteraction.h | 4 +- modules/touch/src/TouchInteraction.cpp | 143 +++++++++++++++++------ 2 files changed, 107 insertions(+), 40 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index a0fabee023..64f3f57059 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -85,7 +85,7 @@ struct FunctionData { std::vector selectedPoints; std::vector screenPoints; int nDOF; - glm::dvec2(*castToScreen)(glm::dvec3, Camera*, SceneGraphNode*, double); + glm::dvec2(*castToScreen)(glm::dvec3, Camera&, SceneGraphNode*, double); double(*distToMinimize)(double* par, int x, void* fdata); Camera* camera; SceneGraphNode* node; @@ -107,7 +107,7 @@ class TouchInteraction : public properties::PropertyOwner void step(double dt); void configSensitivities(double dist); void decelerate(); - glm::dvec2 modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node); + glm::dvec2 modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node, double aspectRatio); void clear(); void tap(); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 06faafbfa3..541e40f96a 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -86,9 +86,71 @@ void TouchInteraction::update(const std::vector& list, std::vector

(fdata); - glm::dvec3 selectedPoint = ptr->selectedPoints.at(x); - glm::dvec3 pointInCamSpace = glm::inverse(ptr->camera->rotationQuaternion()) * (ptr->node->rotationMatrix() * selectedPoint); + glm::dvec3 selectedPoint = ptr->selectedPoints.at(x); + glm::dvec3 pointInWorld = (ptr->node->rotationMatrix() * selectedPoint) + ptr->node->worldPosition(); + // Apply transform to camera and find the new screen point of the updated camera state + double vel[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // { vec2 globalRot, zoom, roll, vec2 localRot } + for (int i = 0; i < ptr->nDOF; ++i) + vel[i] = par[i]; + + using namespace glm; + // Create variables from current state + dvec3 camPos = ptr->camera->positionVec3(); + dvec3 centerPos = ptr->node->worldPosition(); + + dvec3 directionToCenter = normalize(centerPos - camPos); + dvec3 centerToCamera = camPos - centerPos; + dvec3 lookUp = ptr->camera->lookUpVectorWorldSpace(); + dvec3 camDirection = ptr->camera->viewDirectionWorldSpace(); + + // Make a representation of the rotation quaternion with local and global rotations + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction + dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + dquat localCamRot = inverse(globalCamRot) * ptr->camera->rotationQuaternion(); + + { // Roll + dquat camRollRot = angleAxis(vel[3], dvec3(0.0, 0.0, 1.0)); + localCamRot = localCamRot * camRollRot; + } + { // Panning (local rotation) + dvec3 eulerAngles(vel[5], vel[4], 0); + dquat rotationDiff = dquat(eulerAngles); + localCamRot = localCamRot * rotationDiff; + } + { // Orbit (global rotation) + dvec3 eulerAngles(par[1], par[0], 0); + dquat rotationDiffCamSpace = dquat(eulerAngles); + + dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); + dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; + camPos += rotationDiffVec3; + + dvec3 centerToCamera = camPos - centerPos; + directionToCenter = normalize(-centerToCamera); + dvec3 lookUpWhenFacingCenter = globalCamRot * dvec3(ptr->camera->lookUpVectorCameraSpace()); + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + lookUpWhenFacingCenter); + globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + } + { // Zooming + camPos += directionToCenter * vel[2]; + } + + // Update the camera state + Camera cam = *(ptr->camera); + cam.setPositionVec3(camPos); + cam.setRotation(globalCamRot * localCamRot); + + // we now have a new position and orientation of camera, project surfacePoint to the new screen and minimize distance + glm::dvec2 newScreenPoint = ptr->castToScreen(selectedPoint, cam, ptr->node, ptr->aspectRatio); + + /* 2 DOF = trans in XY, 4DOF = trans XYZ + roll case // Create transformation matrix M(q) and apply transform for newPointInModelView glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); glm::dvec3 eulerAngles(0.0, 0.0, 0.0); @@ -102,15 +164,15 @@ void TouchInteraction::update(const std::vector& list, std::vector

camera->rotationQuaternion()) * (ptr->node->rotationMatrix() * selectedPoint); glm::dvec3 newWorldSP = (Q * pointInCamSpace) + T; // cam space around origin - //glm::dvec3 newWorldSP = transform * glm::dvec4(pointInCamSpace, 1.0); // cam space around origin - glm::dvec2 newScreenPoint = ptr->castToScreen(newWorldSP, ptr->camera, ptr->node, ptr->aspectRatio); + glm::dvec2 newScreenPoint = ptr->castToScreen(newWorldSP, ptr->camera, ptr->node, ptr->aspectRatio);*/ + return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; // Gradient (finite derivative) of distToMinimize w.r.t par - auto gradient = [](double* g, double* par, int x, void* fdata) { // should g[i] = 1.0 or the derivative -> project to screen -> .x or .y? + auto gradient = [](double* g, double* par, int x, void* fdata) { FunctionData* ptr = reinterpret_cast(fdata); double f0 = ptr->distToMinimize(par, x, fdata); double f1, h = 1e-4; @@ -129,10 +191,11 @@ void TouchInteraction::update(const std::vector& list, std::vector

worldPosition().x, node->worldPosition().y, node->worldPosition().z, 0.0, 0.0, 0.0 }; for (int i = 0; i < nDOF; ++i) // initial values of q or 0.0? (ie current model or no rotation/translation) par[i] = 0.0; std::vector selectedPoints; @@ -141,26 +204,27 @@ void TouchInteraction::update(const std::vector& list, std::vector

::const_iterator c = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return c.getSessionID() == sb.id; }); - screenPoints.push_back(glm::dvec2(c->getX(), c->getY())); + double xCo = 2 * (c->getX() - 0.5); + double yCo = -2 * (c->getY() - 0.5); // normalized -1 to 1 coordinates on screen + screenPoints.push_back(glm::dvec2(xCo, yCo)); } double* squaredError = new double[nFingers]; // probably not needed for (int i = 0; i < nFingers; ++i) { - double err = glm::length(screenPoints.at(i) - modelToScreenSpace(selectedPoints.at(i), node)); + double err = glm::length(screenPoints.at(i) - modelToScreenSpace(selectedPoints.at(i), node, aspectRatio)); squaredError[i] = err; } - auto castToScreen = [](glm::dvec3 camVec, Camera* camera, SceneGraphNode* node, double aspectRatio) { - glm::dvec3 vecInWorldSpace = camera->rotationQuaternion() * camVec; - glm::dvec3 rayFromCamToPoint = glm::normalize(vecInWorldSpace + node->worldPosition() - camera->positionVec3()); + auto castToScreen = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node, double aspectRatio) { + glm::dvec3 backToScreenSpace = glm::inverse(camera.rotationQuaternion()) + * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera.positionVec3())); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + backToScreenSpace.x /= aspectRatio; - glm::dvec3 pointInNDC = glm::inverse(camera->rotationQuaternion()) * rayFromCamToPoint; - pointInNDC *= (-3.2596558 / pointInNDC.z); - - return glm::dvec2(pointInNDC.x / (2 * aspectRatio) + 0.5, -pointInNDC.y / 2 + 0.5); // returns [0,0] - [1,1] point + return glm::dvec2(backToScreenSpace); }; - glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToScreen, distToMinimize, _camera, node, res.x / res.y }; + + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToScreen, distToMinimize, _camera, node, aspectRatio }; void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); @@ -169,24 +233,21 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationQuaternion() * T; // glm::dvec3(transform[3][0], transform[3][1], transform[3][2]); - - _camera->setPositionVec3(_camera->positionVec3() - worldT); - _camera->rotate(worldQ); + // Set the new camera state + _vel.globalRot = glm::dvec2(temp[0], temp[1]); + _vel.zoom = temp[2]; + _vel.localRoll = temp[3]; + _vel.localRot = glm::dvec2(temp[4], temp[5]); + step(1); + // debugging - std::cout << "Levmarq success after " << nIterations << " iterations. Camera T: " << glm::to_string(worldT) << ", Q: " << glm::to_string(worldQ) << "\n"; + std::ostringstream os; + for (int i = 0; i < nDOF; ++i) { + os << temp[i] << ", "; + } + std::cout << "Levmarq success after " << nIterations << " iterations. Values: " << os.str() << "\n"; // cleanup delete[] squaredError; @@ -477,7 +538,8 @@ void TouchInteraction::step(double dt) { camPos += -directionToCenter * max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); } - configSensitivities(length(camPos - (centerPos + centerToBoundingSphere))); + if (!_directTouchMode) + configSensitivities(length(camPos - (centerPos + centerToBoundingSphere))); decelerate(); // Update the camera state @@ -487,14 +549,13 @@ void TouchInteraction::step(double dt) { } -glm::dvec2 TouchInteraction::modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node) { // probably not needed, if squaredError isnt +glm::dvec2 TouchInteraction::modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node, double aspectRatio) { // probably not needed, if squaredError isnt glm::dvec3 backToScreenSpace = glm::inverse(_camera->rotationQuaternion()) * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - _camera->positionVec3())); backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + backToScreenSpace.x /= aspectRatio; - glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - double aspectRatio = res.x / res.y; - return glm::dvec2(backToScreenSpace.x / (2 * aspectRatio) + 0.5, -backToScreenSpace.y / 2 + 0.5); + return glm::dvec2(backToScreenSpace); } void TouchInteraction::configSensitivities(double dist) { @@ -525,6 +586,12 @@ void TouchInteraction::configSensitivities(double dist) { } void TouchInteraction::decelerate() { + if (_directTouchMode) { + _vel.globalRot = glm::dvec2(0.0, 0.0); + _vel.zoom = 0.0; + _vel.localRoll = 0.0; + _vel.localRot = glm::dvec2(0.0, 0.0); + } _vel.zoom *= (1 - _friction.zoom); _vel.globalRot *= (1 - _friction.globalRot); _vel.localRot *= (1 - _friction.localRot); From b8e6e06aef24d2b40622714a7e20f58d219850c8 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Mon, 24 Apr 2017 08:38:16 -0600 Subject: [PATCH 068/192] include both interaction modes --- ext/ghoul | 2 +- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 47 +++++++++--------------- 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 200401261c..c37ff8beb5 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 200401261cba513fb1faa4b7e92bd213435625ad +Subproject commit c37ff8beb5b8825ecb67b121ae4deac34677e1bd diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 64f3f57059..c81bbcdfdb 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -85,7 +85,7 @@ struct FunctionData { std::vector selectedPoints; std::vector screenPoints; int nDOF; - glm::dvec2(*castToScreen)(glm::dvec3, Camera&, SceneGraphNode*, double); + glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*, double); double(*distToMinimize)(double* par, int x, void* fdata); Camera* camera; SceneGraphNode* node; @@ -107,7 +107,6 @@ class TouchInteraction : public properties::PropertyOwner void step(double dt); void configSensitivities(double dist); void decelerate(); - glm::dvec2 modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node, double aspectRatio); void clear(); void tap(); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 541e40f96a..17893d7d0f 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -86,8 +86,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

(fdata); - glm::dvec3 selectedPoint = ptr->selectedPoints.at(x); - glm::dvec3 pointInWorld = (ptr->node->rotationMatrix() * selectedPoint) + ptr->node->worldPosition(); // Apply transform to camera and find the new screen point of the updated camera state double vel[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // { vec2 globalRot, zoom, roll, vec2 localRot } @@ -122,7 +120,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

castToScreen(selectedPoint, cam, ptr->node, ptr->aspectRatio); + glm::dvec2 newScreenPoint = ptr->castToNDC(ptr->selectedPoints.at(x), cam, ptr->node, ptr->aspectRatio); /* 2 DOF = trans in XY, 4DOF = trans XYZ + roll case // Create transformation matrix M(q) and apply transform for newPointInModelView @@ -182,7 +180,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

nDOF; ++j) { dPar[j] = par[j]; } - dPar[i] += h; f1 = ptr->distToMinimize(dPar, x, fdata); g[i] = (f1 - f0) / h; @@ -193,6 +190,16 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationMatrix() * vec) + node->worldPosition() - camera.positionVec3())); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + backToScreenSpace.x /= aspectRatio; + + return glm::dvec2(backToScreenSpace); + }; + + const int nFingers = list.size(); int nDOF = std::min(nFingers * 2, 6); double* par = new double[nDOF]; @@ -210,21 +217,11 @@ void TouchInteraction::update(const std::vector& list, std::vector

rotationMatrix() * vec) + node->worldPosition() - camera.positionVec3())); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - backToScreenSpace.x /= aspectRatio; - - return glm::dvec2(backToScreenSpace); - }; - - - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToScreen, distToMinimize, _camera, node, aspectRatio }; + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, aspectRatio }; void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); @@ -254,10 +251,10 @@ void TouchInteraction::update(const std::vector& list, std::vector

0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition _directTouchMode = true; @@ -548,16 +545,6 @@ void TouchInteraction::step(double dt) { } } - -glm::dvec2 TouchInteraction::modelToScreenSpace(glm::dvec3 vec, SceneGraphNode* node, double aspectRatio) { // probably not needed, if squaredError isnt - glm::dvec3 backToScreenSpace = glm::inverse(_camera->rotationQuaternion()) - * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - _camera->positionVec3())); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - backToScreenSpace.x /= aspectRatio; - - return glm::dvec2(backToScreenSpace); -} - void TouchInteraction::configSensitivities(double dist) { // Configurates sensitivities to appropriate values when the camera is close to the focus node. std::shared_ptr gbim = From 11906b5aaf871758eb4b6f6d35834f3e83277caa Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Mon, 24 Apr 2017 09:11:01 -0600 Subject: [PATCH 069/192] disable warnings for now --- openspace.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openspace.cfg b/openspace.cfg index 21992234c7..cf331c42ce 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -95,7 +95,7 @@ return { DownloadRequestURL = "http://data.openspaceproject.com/request.cgi", RenderingMethod = "Framebuffer", OpenGLDebugContext = { - Activate = true, + Activate = false, FilterIdentifier = { { Type = "Other", Source = "API", Identifier = 131185 } }, From 556e81afeb52930a736306310c863743dc5b8030 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 25 Apr 2017 13:11:40 -0600 Subject: [PATCH 070/192] fix diagonal-orbit-only bug and cleanup of code --- ext/ghoul | 2 +- modules/touch/ext/levmarq.cpp | 16 +--- modules/touch/ext/levmarq.h | 2 +- modules/touch/src/TouchInteraction.cpp | 103 ++++++++++--------------- modules/touch/touchmodule.cpp | 31 +------- 5 files changed, 49 insertions(+), 105 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 20131b6897..894358db7a 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 20131b68975456d4a90b5cf997dd8f10179a3a31 +Subproject commit 894358db7a1e15d7ae81a251aa2062ae8a48fa87 diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 6f690930dc..a179fb9ec5 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,7 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 0; + lmstat->verbose = 1; lmstat->max_it = 5000; lmstat->init_lambda = 1e-6; lmstat->up_factor = 10; @@ -57,7 +57,7 @@ The arguments are as follows: Before calling levmarq, several of the parameters in lmstat must be set. For default values, call levmarq_init(lmstat). */ -int levmarq(int npar, double *par, int ny, double* y, double *dysq, +bool levmarq(int npar, double *par, int ny, double *dysq, double (*func)(double *, int, void *), void (*grad)(double *, double *, int, void *), void *fdata, LMstat *lmstat) { @@ -123,15 +123,7 @@ int levmarq(int npar, double *par, int ny, double* y, double *dysq, ill = (derr > 0); } if (verbose) { - printf("it = %4d, newerror = %10g, err = %10g, derr = %10g\n", it, newerr, err, derr); - for (i = 0; i < npar; i++) { - printf("%f:", par[i]); - } - printf("\n"); - for (i = 0; i < npar; ++i) { - printf("%f:", delta[i]); - } - printf("\n"); + printf("it = %4d, lambda = %10g, err = %10g, derr = %10g (%d)\n", it, lambda, err, derr, !(newerr > err)); } if (ill) { mult = (1 + lambda * up) / (1 + lambda); @@ -164,7 +156,7 @@ int levmarq(int npar, double *par, int ny, double* y, double *dysq, delete[] delta; delete[] newpar; - return it; + return (it != lmstat->max_it); } diff --git a/modules/touch/ext/levmarq.h b/modules/touch/ext/levmarq.h index 4dad30e0a1..0009cc1324 100644 --- a/modules/touch/ext/levmarq.h +++ b/modules/touch/ext/levmarq.h @@ -38,7 +38,7 @@ typedef struct { void levmarq_init(LMstat *lmstat); -int levmarq(int npar, double *par, int ny, double* y, double *dysq, +bool levmarq(int npar, double *par, int ny, double *dysq, double (*func)(double *, int, void *), void (*grad)(double *, double *, int, void *), void *fdata, LMstat *lmstat); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 17893d7d0f..1198f3e62a 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -82,15 +82,16 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { // should just be a function call + if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { // code below should just be a function call + // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi auto distToMinimize = [](double* par, int x, void* fdata) { FunctionData* ptr = reinterpret_cast(fdata); // Apply transform to camera and find the new screen point of the updated camera state - double vel[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // { vec2 globalRot, zoom, roll, vec2 localRot } + double q[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // { vec2 globalRot, zoom, roll, vec2 localRot } for (int i = 0; i < ptr->nDOF; ++i) - vel[i] = par[i]; + q[i] = par[i]; using namespace glm; // Create variables from current state @@ -111,16 +112,16 @@ void TouchInteraction::update(const std::vector& list, std::vector

camera->rotationQuaternion(); { // Roll - dquat camRollRot = angleAxis(vel[3], dvec3(0.0, 0.0, 1.0)); + dquat camRollRot = angleAxis(q[3], dvec3(0.0, 0.0, 1.0)); localCamRot = localCamRot * camRollRot; } { // Panning (local rotation) - dvec3 eulerAngles(vel[5], vel[4], 0); + dvec3 eulerAngles(q[5], q[4], 0); dquat rotationDiff = dquat(eulerAngles); localCamRot = localCamRot * rotationDiff; } { // Orbit (global rotation) - dvec3 eulerAngles(vel[1], vel[0], 0); + dvec3 eulerAngles(q[1], q[0], 0); dquat rotationDiffCamSpace = dquat(eulerAngles); dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); @@ -137,7 +138,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list, std::vector

castToNDC(ptr->selectedPoints.at(x), cam, ptr->node, ptr->aspectRatio); - - /* 2 DOF = trans in XY, 4DOF = trans XYZ + roll case - // Create transformation matrix M(q) and apply transform for newPointInModelView - glm::dvec3 T = glm::dvec3(par[0], par[1], 0.0); - glm::dvec3 eulerAngles(0.0, 0.0, 0.0); - double twoPi = 2.0 * M_PI; - if (ptr->nDOF > 2) { // need to check how many DOF we can handle (+2 DOF per finger down up to 6) - T.z = par[2]; - eulerAngles.z = fmod(par[3], twoPi); - if (ptr->nDOF > 4) { - eulerAngles.y = fmod(par[4], twoPi); - eulerAngles.x = fmod(par[5], twoPi); - } - } - glm::dquat Q = glm::normalize(glm::dquat(eulerAngles)); - glm::dvec3 pointInCamSpace = glm::inverse(ptr->camera->rotationQuaternion()) * (ptr->node->rotationMatrix() * selectedPoint); - glm::dvec3 newWorldSP = (Q * pointInCamSpace) + T; // cam space around origin - - glm::dvec2 newScreenPoint = ptr->castToScreen(newWorldSP, ptr->camera, ptr->node, ptr->aspectRatio);*/ return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; @@ -173,23 +155,23 @@ void TouchInteraction::update(const std::vector& list, std::vector

(fdata); double f0 = ptr->distToMinimize(par, x, fdata); - double f1, h = 1e-4; + double f1, der, h; double* dPar = new double[ptr->nDOF]; - + for (int i = 0; i < ptr->nDOF; ++i) { for (int j = 0; j < ptr->nDOF; ++j) { dPar[j] = par[j]; } + h = (i == 2) ? 1e-4: 1e-10; dPar[i] += h; f1 = ptr->distToMinimize(dPar, x, fdata); - g[i] = (f1 - f0) / h; + der = (f1 - f0) / h; + g[i] = (i > 1 && i < 4) ? der : der / abs(der); } delete[] dPar; }; SceneGraphNode* node = _selected.at(0).node; - glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - double aspectRatio = res.x / res.y; auto castToNDC = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node, double aspectRatio) { glm::dvec3 backToScreenSpace = glm::inverse(camera.rotationQuaternion()) * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera.positionVec3())); @@ -203,8 +185,9 @@ void TouchInteraction::update(const std::vector& list, std::vector

selectedPoints; std::vector screenPoints; for (const SelectedBody& sb : _selected) { @@ -215,39 +198,34 @@ void TouchInteraction::update(const std::vector& list, std::vector

getY() - 0.5); // normalized -1 to 1 coordinates on screen screenPoints.push_back(glm::dvec2(xCo, yCo)); } - double* squaredError = new double[nFingers]; // probably not needed - for (int i = 0; i < nFingers; ++i) { - double err = glm::length(screenPoints.at(i) - castToNDC(selectedPoints.at(i), *_camera, node, aspectRatio)); - squaredError[i] = err; - } - - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, aspectRatio }; + glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, res.x / res.y }; void* dataPtr = reinterpret_cast(&fData); levmarq_init(&_lmstat); - int nIterations = levmarq(nDOF, par, nFingers, squaredError, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par + bool success = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - double temp[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - for (int i = 0; i < nDOF; ++i) - temp[i] = par[i]; + if (success) { // if good values were found set new camera state + _vel.globalRot = glm::dvec2(par[0], par[1]); + if (nDOF > 2) { + _vel.zoom = par[2]; + _vel.localRoll = par[3]; + if (nDOF > 4) { + _vel.localRot = glm::dvec2(par[4], par[5]); + } + } + step(1); + } - // Set the new camera state - _vel.globalRot = glm::dvec2(temp[0], temp[1]); - _vel.zoom = temp[2]; - _vel.localRoll = temp[3]; - _vel.localRot = glm::dvec2(temp[4], temp[5]); - step(1); - // debugging - std::ostringstream os; + /*std::ostringstream os; for (int i = 0; i < nDOF; ++i) { - os << temp[i] << ", "; + os << par[i] << ", "; } - std::cout << "Levmarq success after " << nIterations << " iterations. Values: " << os.str() << "\n"; + std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ // cleanup - delete[] squaredError; delete[] par; } trace(list); @@ -426,9 +404,9 @@ void TouchInteraction::accelerate(const std::vector& list, const std double res = diff; double lastAngle = point.getAngle(_centroid.x, _centroid.y); double currentAngle = c.getAngle(_centroid.x, _centroid.y); - if (lastAngle > currentAngle + 1.5*M_PI) + if (lastAngle > currentAngle + 1.5 * M_PI) res += currentAngle + (2 * M_PI - lastAngle); - else if (currentAngle > lastAngle + 1.5*M_PI) + else if (currentAngle > lastAngle + 1.5 * M_PI) res += (2 * M_PI - currentAngle) + lastAngle; else res += currentAngle - lastAngle; @@ -529,16 +507,15 @@ void TouchInteraction::step(double dt) { dquat camRollRot = angleAxis(_vel.globalRoll*dt, -directionToCenter); globalCamRot = camRollRot * globalCamRot; } - { // Push up to surface + if (!_directTouchMode) { // Push up to surface dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere); double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera); camPos += -directionToCenter * max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); - } - - if (!_directTouchMode) - configSensitivities(length(camPos - (centerPos + centerToBoundingSphere))); - decelerate(); + configSensitivities(length(camPos - (centerPos + centerToBoundingSphere))); // might not be needed when direct touch is active + } + + decelerate(); // Update the camera state _camera->setPositionVec3(camPos); _camera->setRotation(globalCamRot * localCamRot); diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 243084d9df..9df406b9d9 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -128,36 +128,11 @@ TouchModule::TouchModule() if (gotNewInput() && OsEng.windowWrapper().isMaster()) { touch->update(list, lastProcessed); - - // for debugging - //std::this_thread::sleep_for(std::chrono::seconds(1)); - std::ostringstream os; - for (const TuioCursor &j : list) { // go through each item - std::list path = j.getPath(); - - TuioTime lastTime = find_if( - lastProcessed.begin(), - lastProcessed.end(), - [&j](const Point& p) { return p.first == j.getSessionID(); } - )->second.getTuioTime(); - - std::list::iterator lastPoint = find_if( - path.begin(), - path.end(), - [&lastTime](const TuioPoint& c) { return lastTime == c.getTuioTime(); }); - - int count = -1; - for (; lastPoint != path.end(); ++lastPoint) // here we can access all elements that are to be processed - count++; - - os << ", Id: " << j.getCursorID() << ", path size: " << j.getPath().size() << ", To Process: " << count; - } - //LINFO("List size: " << list.size() << os.str() << "\n"); - os.clear(); - + //std::this_thread::sleep_for(std::chrono::seconds(1)); // for debugging } - else if (list.size() == 0) + else if (list.size() == 0) { touch->clear(); + } // update lastProcessed lastProcessed.clear(); From b5a058121d4fa68eb491886cc1f6bbaa2e64969d Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 25 Apr 2017 17:06:46 -0600 Subject: [PATCH 071/192] put direct-manipulation in its own function, dynamic time step for all but the zoom-DOF --- modules/touch/ext/levmarq.cpp | 6 +- modules/touch/include/TouchInteraction.h | 1 + modules/touch/src/TouchInteraction.cpp | 329 +++++++++++++---------- openspace.cfg | 2 +- 4 files changed, 185 insertions(+), 153 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index a179fb9ec5..b0add0228a 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,11 +30,11 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 1; + lmstat->verbose = 0; lmstat->max_it = 5000; lmstat->init_lambda = 1e-6; - lmstat->up_factor = 10; - lmstat->down_factor = 10; + lmstat->up_factor = 5; + lmstat->down_factor = 5; lmstat->target_derr = 1e-12; } diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index c81bbcdfdb..d1a0edf507 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -101,6 +101,7 @@ class TouchInteraction : public properties::PropertyOwner ~TouchInteraction(); void update(const std::vector& list, std::vector& lastProcessed); + void manipulate(const std::vector& list); void trace(const std::vector& list); void interpret(const std::vector& list, const std::vector& lastProcessed); void accelerate(const std::vector& list, const std::vector& lastProcessed); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 1198f3e62a..bba7227341 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -82,151 +82,8 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { // code below should just be a function call - - // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi - auto distToMinimize = [](double* par, int x, void* fdata) { - FunctionData* ptr = reinterpret_cast(fdata); - - // Apply transform to camera and find the new screen point of the updated camera state - double q[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // { vec2 globalRot, zoom, roll, vec2 localRot } - for (int i = 0; i < ptr->nDOF; ++i) - q[i] = par[i]; - - using namespace glm; - // Create variables from current state - dvec3 camPos = ptr->camera->positionVec3(); - dvec3 centerPos = ptr->node->worldPosition(); - - dvec3 directionToCenter = normalize(centerPos - camPos); - dvec3 centerToCamera = camPos - centerPos; - dvec3 lookUp = ptr->camera->lookUpVectorWorldSpace(); - dvec3 camDirection = ptr->camera->viewDirectionWorldSpace(); - - // Make a representation of the rotation quaternion with local and global rotations - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - directionToCenter, - normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction - dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - dquat localCamRot = inverse(globalCamRot) * ptr->camera->rotationQuaternion(); - - { // Roll - dquat camRollRot = angleAxis(q[3], dvec3(0.0, 0.0, 1.0)); - localCamRot = localCamRot * camRollRot; - } - { // Panning (local rotation) - dvec3 eulerAngles(q[5], q[4], 0); - dquat rotationDiff = dquat(eulerAngles); - localCamRot = localCamRot * rotationDiff; - } - { // Orbit (global rotation) - dvec3 eulerAngles(q[1], q[0], 0); - dquat rotationDiffCamSpace = dquat(eulerAngles); - - dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); - dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; - camPos += rotationDiffVec3; - - dvec3 centerToCamera = camPos - centerPos; - directionToCenter = normalize(-centerToCamera); - dvec3 lookUpWhenFacingCenter = globalCamRot * dvec3(ptr->camera->lookUpVectorCameraSpace()); - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - directionToCenter, - lookUpWhenFacingCenter); - globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - } - { // Zooming - camPos += directionToCenter * q[2]; - } - - // Update the camera state - Camera cam = *(ptr->camera); - cam.setPositionVec3(camPos); - cam.setRotation(globalCamRot * localCamRot); - - // we now have a new position and orientation of camera, project surfacePoint to the new screen to get distance to minimize - glm::dvec2 newScreenPoint = ptr->castToNDC(ptr->selectedPoints.at(x), cam, ptr->node, ptr->aspectRatio); - - return glm::length(ptr->screenPoints.at(x) - newScreenPoint); - }; - // Gradient (finite derivative) of distToMinimize w.r.t par - auto gradient = [](double* g, double* par, int x, void* fdata) { - FunctionData* ptr = reinterpret_cast(fdata); - double f0 = ptr->distToMinimize(par, x, fdata); - double f1, der, h; - double* dPar = new double[ptr->nDOF]; - - for (int i = 0; i < ptr->nDOF; ++i) { - for (int j = 0; j < ptr->nDOF; ++j) { - dPar[j] = par[j]; - } - h = (i == 2) ? 1e-4: 1e-10; - dPar[i] += h; - f1 = ptr->distToMinimize(dPar, x, fdata); - der = (f1 - f0) / h; - g[i] = (i > 1 && i < 4) ? der : der / abs(der); - } - delete[] dPar; - }; - - SceneGraphNode* node = _selected.at(0).node; - auto castToNDC = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node, double aspectRatio) { - glm::dvec3 backToScreenSpace = glm::inverse(camera.rotationQuaternion()) - * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera.positionVec3())); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - backToScreenSpace.x /= aspectRatio; - - return glm::dvec2(backToScreenSpace); - }; - - - const int nFingers = list.size(); - int nDOF = std::min(nFingers * 2, 6); - double* par = new double[nDOF]; - for (int i = 0; i < nDOF; ++i) { // initial values of q or 0.0? (ie current model or no rotation/translation) - par[i] = 0.0; - } - std::vector selectedPoints; - std::vector screenPoints; - for (const SelectedBody& sb : _selected) { - selectedPoints.push_back(sb.coordinates); - - std::vector::const_iterator c = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return c.getSessionID() == sb.id; }); - double xCo = 2 * (c->getX() - 0.5); - double yCo = -2 * (c->getY() - 0.5); // normalized -1 to 1 coordinates on screen - screenPoints.push_back(glm::dvec2(xCo, yCo)); - } - glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, res.x / res.y }; - void* dataPtr = reinterpret_cast(&fData); - - levmarq_init(&_lmstat); - bool success = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - - if (success) { // if good values were found set new camera state - _vel.globalRot = glm::dvec2(par[0], par[1]); - if (nDOF > 2) { - _vel.zoom = par[2]; - _vel.localRoll = par[3]; - if (nDOF > 4) { - _vel.localRot = glm::dvec2(par[4], par[5]); - } - } - step(1); - } - - - // debugging - /*std::ostringstream os; - for (int i = 0; i < nDOF; ++i) { - os << par[i] << ", "; - } - std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ - - // cleanup - delete[] par; + if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { + manipulate(list); } trace(list); if (!_directTouchMode) { @@ -242,6 +99,156 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list) { + // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi + auto distToMinimize = [](double* par, int x, void* fdata) { + FunctionData* ptr = reinterpret_cast(fdata); + + // Apply transform to camera and find the new screen point of the updated camera state + double q[6] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; // { vec2 globalRot, zoom, roll, vec2 localRot } + for (int i = 0; i < ptr->nDOF; ++i) { + q[i] = par[i]; + } + + using namespace glm; + // Create variables from current state + dvec3 camPos = ptr->camera->positionVec3(); + dvec3 centerPos = ptr->node->worldPosition(); + + dvec3 directionToCenter = normalize(centerPos - camPos); + dvec3 centerToCamera = camPos - centerPos; + dvec3 lookUp = ptr->camera->lookUpVectorWorldSpace(); + dvec3 camDirection = ptr->camera->viewDirectionWorldSpace(); + + // Make a representation of the rotation quaternion with local and global rotations + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction + dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + dquat localCamRot = inverse(globalCamRot) * ptr->camera->rotationQuaternion(); + + { // Roll + dquat camRollRot = angleAxis(q[3], dvec3(0.0, 0.0, 1.0)); + localCamRot = localCamRot * camRollRot; + } + { // Panning (local rotation) + dvec3 eulerAngles(q[5], q[4], 0); + dquat rotationDiff = dquat(eulerAngles); + localCamRot = localCamRot * rotationDiff; + } + { // Orbit (global rotation) + dvec3 eulerAngles(q[1], q[0], 0); + dquat rotationDiffCamSpace = dquat(eulerAngles); + + dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); + dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; + camPos += rotationDiffVec3; + + dvec3 centerToCamera = camPos - centerPos; + directionToCenter = normalize(-centerToCamera); + dvec3 lookUpWhenFacingCenter = globalCamRot * dvec3(ptr->camera->lookUpVectorCameraSpace()); + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + directionToCenter, + lookUpWhenFacingCenter); + globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + } + { // Zooming + camPos += directionToCenter * q[2]; + } + + // Update the camera state + Camera cam = *(ptr->camera); + cam.setPositionVec3(camPos); + cam.setRotation(globalCamRot * localCamRot); + + // we now have a new position and orientation of camera, project surfacePoint to the new screen to get distance to minimize + glm::dvec2 newScreenPoint = ptr->castToNDC(ptr->selectedPoints.at(x), cam, ptr->node, ptr->aspectRatio); + + return glm::length(ptr->screenPoints.at(x) - newScreenPoint); + }; + // Gradient (finite derivative) of distToMinimize w.r.t par + auto gradient = [](double* g, double* par, int x, void* fdata) { + FunctionData* ptr = reinterpret_cast(fdata); + double f0 = ptr->distToMinimize(par, x, fdata); + double f1, der, minStep = 1e-11; + glm::dvec3 camPos = ptr->camera->positionVec3(); + glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); + double h = minStep * glm::distance(camPos, selectedPoint); + double* dPar = new double[ptr->nDOF]; + + for (int i = 0; i < ptr->nDOF; ++i) { + for (int j = 0; j < ptr->nDOF; ++j) { + dPar[j] = par[j]; + } + h = (i == 2) ? 1e-4 : h; // the 'zoom'-DOF is so big a smaller step creates NAN + dPar[i] += h; + f1 = ptr->distToMinimize(dPar, x, fdata); + der = (f1 - f0) / h; + g[i] = (i > 1 && i < 4) ? der : der / abs(der); + } + delete[] dPar; + }; + + SceneGraphNode* node = _selected.at(0).node; + auto castToNDC = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node, double aspectRatio) { + glm::dvec3 backToScreenSpace = glm::inverse(camera.rotationQuaternion()) + * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera.positionVec3())); + backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); + backToScreenSpace.x /= aspectRatio; + + return glm::dvec2(backToScreenSpace); + }; + + const int nFingers = list.size(); + int nDOF = std::min(nFingers * 2, 6); + double* par = new double[nDOF]; + for (int i = 0; i < nDOF; ++i) { // initial values of q or 0.0? (ie current model or no rotation/translation) + par[i] = 0.0; + } + std::vector selectedPoints; + std::vector screenPoints; + for (const SelectedBody& sb : _selected) { + selectedPoints.push_back(sb.coordinates); + + std::vector::const_iterator c = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return c.getSessionID() == sb.id; }); + double xCo = 2 * (c->getX() - 0.5); + double yCo = -2 * (c->getY() - 0.5); // normalized -1 to 1 coordinates on screen + screenPoints.push_back(glm::dvec2(xCo, yCo)); + } + glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, res.x / res.y }; + void* dataPtr = reinterpret_cast(&fData); + + levmarq_init(&_lmstat); + bool success = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par + + if (success) { // if good values were found set new camera state + _vel.globalRot = glm::dvec2(par[0], par[1]); + if (nDOF > 2) { + _vel.zoom = par[2]; + _vel.localRoll = par[3]; + if (nDOF > 4) { + _vel.localRot = glm::dvec2(par[4], par[5]); + } + } + step(1); + } + + // debugging + /*std::ostringstream os; + for (int i = 0; i < nDOF; ++i) { + os << par[i] << ", "; + } + std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ + + // cleanup + delete[] par; +} + +// Traces the touch input into the scene and finds the surface coordinates of touched planets (if occuring) void TouchInteraction::trace(const std::vector& list) { //trim list to only contain visible nodes that make sense @@ -305,6 +312,7 @@ void TouchInteraction::trace(const std::vector& list) { _selected = newSelected; } +// Interprets the input gesture to a specific interaction void TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { double dist = 0; double lastDist = 0; @@ -373,6 +381,7 @@ void TouchInteraction::interpret(const std::vector& list, const std: } } +// Calculate how much interpreted interaction should change the camera state (based on _vel) void TouchInteraction::accelerate(const std::vector& list, const std::vector& lastProcessed) { TuioCursor cursor = list.at(0); if (!_action.rot || !_action.pick) { @@ -420,10 +429,30 @@ void TouchInteraction::accelerate(const std::vector& list, const std _focusNode = _selected.at(0).node; // rotate camera to look at new focus OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode glm::dvec3 camToFocus = glm::normalize(_focusNode->worldPosition() - _camera->positionVec3()); - double angleX = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * _camera->lookUpVectorWorldSpace())); - double angleY = glm::orientedAngle(_camera->viewDirectionWorldSpace(), camToFocus, glm::normalize(_camera->rotationQuaternion() * glm::dvec3(1,0,0))); - //std::cout << "x: " << angleX << ", y: " << angleY << "\n"; - _vel.localRot = _sensitivity.localRot * glm::dvec2(-angleX, -angleY); + glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); + glm::dvec3 camUp = glm::normalize(_camera->lookUpVectorWorldSpace()); + glm::dvec3 camRight = glm::normalize(glm::cross(camUp, camForward)); + + + glm::dvec2 angles = glm::dvec2(0.0); + + + glm::dvec3 directionToCenter = normalize(_focusNode->worldPosition() - _camera->positionVec3()); + glm::dvec3 lookUp = _camera->lookUpVectorWorldSpace(); + glm::dvec3 camDirection = _camera->viewDirectionWorldSpace(); + + // Make a representation of the rotation quaternion with local and global rotations + glm::dmat4 lookAtMat = lookAt( + glm::dvec3(0, 0, 0), + directionToCenter, + glm::normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction + glm::dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + glm::dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion() * glm::dquat(glm::dvec3(angles.y, angles.x, 0.0)); + + _camera->setRotation(globalCamRot * localCamRot); + /// + + } else { // should zoom in to current _selected.coordinates position double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); @@ -439,6 +468,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std } } +// Main update call, calculates the new orientation and position for the camera depending on _vel and dt. Called every frame void TouchInteraction::step(double dt) { using namespace glm; @@ -522,6 +552,7 @@ void TouchInteraction::step(double dt) { } } +// Might not be needed with direct-manipulation void TouchInteraction::configSensitivities(double dist) { // Configurates sensitivities to appropriate values when the camera is close to the focus node. std::shared_ptr gbim = diff --git a/openspace.cfg b/openspace.cfg index cf331c42ce..6790350464 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -26,7 +26,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/globebrowsing.scene", + Scene = "${SCENE}/default.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", From 9111151913db2fee438bbb62f0e05b79fd910a96 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 26 Apr 2017 16:10:23 -0600 Subject: [PATCH 072/192] Using slerp to interpolate to new local rotation when choosing new focusnode, tried central difference on gradient calc to resolve zoom/roll bug --- modules/touch/ext/levmarq.cpp | 4 +- modules/touch/include/TouchInteraction.h | 2 + modules/touch/src/TouchInteraction.cpp | 57 +++++++++++------------- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index b0add0228a..a36a0605ca 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -33,8 +33,8 @@ void levmarq_init(LMstat *lmstat) { lmstat->verbose = 0; lmstat->max_it = 5000; lmstat->init_lambda = 1e-6; - lmstat->up_factor = 5; - lmstat->down_factor = 5; + lmstat->up_factor = 10; + lmstat->down_factor = 10; lmstat->target_derr = 1e-12; } diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index d1a0edf507..2d1a57d56a 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -144,6 +144,8 @@ class TouchInteraction : public properties::PropertyOwner LMstat _lmstat; glm::dvec3 _centroid; + glm::dquat _toSlerp; + double _time; VelocityStates _vel; ScaleFactor _friction; ScaleFactor _sensitivity; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index bba7227341..41162e5f6f 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -65,6 +65,7 @@ TouchInteraction::TouchInteraction() _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _currentRadius{ 1.0 }, + _time{ 0.0 }, _directTouchMode{ false }, _tap{ false } { addProperty(_touchScreenSize); @@ -169,24 +170,26 @@ void TouchInteraction::manipulate(const std::vector& list) { return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; - // Gradient (finite derivative) of distToMinimize w.r.t par + // Gradient of distToMinimize w.r.t par (using central difference) auto gradient = [](double* g, double* par, int x, void* fdata) { FunctionData* ptr = reinterpret_cast(fdata); double f0 = ptr->distToMinimize(par, x, fdata); - double f1, der, minStep = 1e-11; + double f1, f2, der, minStep = 1e-11; glm::dvec3 camPos = ptr->camera->positionVec3(); glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); double h = minStep * glm::distance(camPos, selectedPoint); double* dPar = new double[ptr->nDOF]; + for (int i = 0; i < ptr->nDOF; ++i) { + dPar[i] = par[i]; + } for (int i = 0; i < ptr->nDOF; ++i) { - for (int j = 0; j < ptr->nDOF; ++j) { - dPar[j] = par[j]; - } h = (i == 2) ? 1e-4 : h; // the 'zoom'-DOF is so big a smaller step creates NAN dPar[i] += h; f1 = ptr->distToMinimize(dPar, x, fdata); + dPar[i] -= h; der = (f1 - f0) / h; + g[i] = (i > 1 && i < 4) ? der : der / abs(der); } delete[] dPar; @@ -357,14 +360,14 @@ void TouchInteraction::interpret(const std::vector& list, const std: _action.pick = false; } else { - if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 2) { + if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 3) { _action.rot = false; _action.pinch = false; _action.pan = true; _action.roll = false; _action.pick = false; } - else if (list.size() > 2 && std::abs(minDiff) < 0.0008) { + else if (list.size() > 1 && std::abs(minDiff) < 0.0008) { // if one finger is still and another moving, we have roll _action.rot = false; _action.pinch = false; _action.pan = false; @@ -428,33 +431,19 @@ void TouchInteraction::accelerate(const std::vector& list, const std if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { _focusNode = _selected.at(0).node; // rotate camera to look at new focus OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode - glm::dvec3 camToFocus = glm::normalize(_focusNode->worldPosition() - _camera->positionVec3()); - glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); + glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); glm::dvec3 camUp = glm::normalize(_camera->lookUpVectorWorldSpace()); - glm::dvec3 camRight = glm::normalize(glm::cross(camUp, camForward)); - - - glm::dvec2 angles = glm::dvec2(0.0); - - - glm::dvec3 directionToCenter = normalize(_focusNode->worldPosition() - _camera->positionVec3()); - glm::dvec3 lookUp = _camera->lookUpVectorWorldSpace(); - glm::dvec3 camDirection = _camera->viewDirectionWorldSpace(); - - // Make a representation of the rotation quaternion with local and global rotations - glm::dmat4 lookAtMat = lookAt( - glm::dvec3(0, 0, 0), - directionToCenter, - glm::normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction - glm::dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - glm::dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion() * glm::dquat(glm::dvec3(angles.y, angles.x, 0.0)); - - _camera->setRotation(globalCamRot * localCamRot); - /// - + glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); + double angle = glm::angle(camForward, camToFocus); + glm::dvec3 axis = glm::normalize(glm::cross(camForward, camToFocus)); + _toSlerp.x = axis.x * sin(angle / 2.0); + _toSlerp.y = axis.y * sin(angle / 2.0); + _toSlerp.z = axis.z * sin(angle / 2.0); + _toSlerp.w = cos(angle / 2.0); + _time = 0.0; } - else { // should zoom in to current _selected.coordinates position + else { // should zoom in to current _selected.coordinates position but not further than _directTouchMode activation double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); double startDecline = _focusNode->boundingSphere() / (0.15 * _projectionScaleFactor); double factor = 2.0; @@ -507,6 +496,12 @@ void TouchInteraction::step(double dt) { dvec3 eulerAngles(_vel.localRot.y*dt, _vel.localRot.x*dt, 0); dquat rotationDiff = dquat(eulerAngles); localCamRot = localCamRot * rotationDiff; + + // if we have chosen a new focus node + if (_time < 1) { + _time += 0.5 * dt; + localCamRot = slerp(localCamRot, _toSlerp, _time); + } } { // Orbit (global rotation) dvec3 eulerAngles(_vel.globalRot.y*dt, _vel.globalRot.x*dt, 0); From 86d02fc98b0185e0f5d9e8b158dbb3f810a934b5 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 27 Apr 2017 12:44:32 -0600 Subject: [PATCH 073/192] Refactor TouchInteraction class (removed unneeded variables/functions and went back to switch-case for interpret() --- modules/touch/include/TouchInteraction.h | 58 ++--- modules/touch/src/TouchInteraction.cpp | 270 +++++++++-------------- openspace.cfg | 2 +- 3 files changed, 125 insertions(+), 205 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 2d1a57d56a..37d266b460 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -68,19 +68,11 @@ struct ScaleFactor { double globalRoll; double localRoll; }; -struct InteractionType { - bool rot; - bool pinch; - bool pan; - bool roll; - bool pick; -}; struct SelectedBody { int id; SceneGraphNode* node; glm::dvec3 coordinates; }; - struct FunctionData { std::vector selectedPoints; std::vector screenPoints; @@ -92,6 +84,12 @@ struct FunctionData { double aspectRatio; }; +#define ROT 0 +#define PINCH 1 +#define ROLL 2 +#define PAN 3 +#define PICK 4 + using Point = std::pair; class TouchInteraction : public properties::PropertyOwner @@ -103,10 +101,11 @@ class TouchInteraction : public properties::PropertyOwner void update(const std::vector& list, std::vector& lastProcessed); void manipulate(const std::vector& list); void trace(const std::vector& list); - void interpret(const std::vector& list, const std::vector& lastProcessed); + int interpret(const std::vector& list, const std::vector& lastProcessed); void accelerate(const std::vector& list, const std::vector& lastProcessed); + void step(double dt); - void configSensitivities(double dist); + void decelerate(); void clear(); void tap(); @@ -114,42 +113,29 @@ class TouchInteraction : public properties::PropertyOwner // Get & Setters Camera* getCamera(); SceneGraphNode* getFocusNode(); - double getFriction(); - double getSensitivity(); - void setFocusNode(SceneGraphNode* focusNode); void setCamera(Camera* cam); - void setFriction(double friction); - void setSensitivity(double sensitivity); private: - - // could be removed - double _baseSensitivity; - double _baseFriction; - double _minHeightFromSurface; - Camera* _camera; SceneGraphNode* _focusNode = nullptr; - properties::StringProperty _origin; - properties::Vec2Property _touchScreenSize; - globebrowsing::RenderableGlobe* _globe; - bool _tap; - bool _directTouchMode; - double _projectionScaleFactor; - double _currentRadius; - std::vector _selected; - InteractionType _action; - - LMstat _lmstat; - glm::dvec3 _centroid; - glm::dquat _toSlerp; - double _time; + properties::StringProperty _origin; VelocityStates _vel; ScaleFactor _friction; ScaleFactor _sensitivity; - + glm::dvec3 _centroid; + int _action; + double _projectionScaleFactor; + double _currentRadius; + double _time; + bool _directTouchMode; + bool _tap; + properties::Vec2Property _touchScreenSize; + + std::vector _selected; + LMstat _lmstat; + glm::dquat _toSlerp; }; } // openspace namespace diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 41162e5f6f..ca599ed8cb 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -57,16 +57,16 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), - _baseSensitivity{ 0.1 }, _baseFriction{ 0.02 }, _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, - _friction{ _baseFriction, _baseFriction/2.0, _baseFriction, _baseFriction, _baseFriction }, - _touchScreenSize("TouchScreenSize", "Touch Screen Normalizer", glm::vec2(122, 68), glm::vec2(0), glm::vec2(1000)), // glm::vec2(width, height) in cm. (13.81, 6.7) for iphone 6s plus + _friction{ 0.02, 0.01, 0.02, 0.02, 0.02 }, + _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, _centroid{ glm::dvec3(0.0) }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, + _action{ -1 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, - _time{ 0.0 }, - _directTouchMode{ false }, _tap{ false } + _currentRadius{ 1.0 }, _time{ 1.0 }, + _directTouchMode{ false }, _tap{ false }, + _touchScreenSize("TouchScreenSize", "Touch Screen Normalizer", glm::vec2(122, 68), glm::vec2(0), glm::vec2(1000)) + // glm::vec2(width, height) in cm. (13.81, 6.7) for iphone 6s plus { addProperty(_touchScreenSize); levmarq_init(&_lmstat); @@ -82,13 +82,14 @@ TouchInteraction::TouchInteraction() TouchInteraction::~TouchInteraction() { } +// Called each frame if there is any input void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { manipulate(list); } trace(list); if (!_directTouchMode) { - interpret(list, lastProcessed); + _action = interpret(list, lastProcessed); accelerate(list, lastProcessed); } @@ -170,11 +171,11 @@ void TouchInteraction::manipulate(const std::vector& list) { return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; - // Gradient of distToMinimize w.r.t par (using central difference) + // Gradient of distToMinimize w.r.t par (using forward difference) auto gradient = [](double* g, double* par, int x, void* fdata) { FunctionData* ptr = reinterpret_cast(fdata); double f0 = ptr->distToMinimize(par, x, fdata); - double f1, f2, der, minStep = 1e-11; + double f1, der, minStep = 1e-11; glm::dvec3 camPos = ptr->camera->positionVec3(); glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); double h = minStep * glm::distance(camPos, selectedPoint); @@ -225,7 +226,6 @@ void TouchInteraction::manipulate(const std::vector& list) { FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, res.x / res.y }; void* dataPtr = reinterpret_cast(&fData); - levmarq_init(&_lmstat); bool success = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par if (success) { // if good values were found set new camera state @@ -316,7 +316,7 @@ void TouchInteraction::trace(const std::vector& list) { } // Interprets the input gesture to a specific interaction -void TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { +int TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { double dist = 0; double lastDist = 0; TuioCursor cursor = list.at(0); @@ -346,40 +346,20 @@ void TouchInteraction::interpret(const std::vector& list, const std: } if (_tap) { _tap = false; - _action.rot = false; - _action.pinch = false; - _action.pan = false; - _action.roll = false; - _action.pick = true; + return PICK; } else if (list.size() == 1) { - _action.rot = true; - _action.pinch = false; - _action.pan = false; - _action.roll = false; - _action.pick = false; + return ROT; } else { - if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 3) { - _action.rot = false; - _action.pinch = false; - _action.pan = true; - _action.roll = false; - _action.pick = false; + if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 3) { // if distance between fingers is constant we have panning + return PAN; } - else if (list.size() > 1 && std::abs(minDiff) < 0.0008) { // if one finger is still and another moving, we have roll - _action.rot = false; - _action.pinch = false; - _action.pan = false; - _action.roll = true; - _action.pick = false; + else if (list.size() > 1 && std::abs(minDiff) < 0.0008) { // if one finger is 'still' (0.0008 works as epsilon) and another moving, we have roll + return ROLL; } else { - _action.rot = false; - _action.pinch = true; - _action.pan = false; - _action.roll = false; - _action.pick = false; + return PINCH; } } } @@ -387,73 +367,77 @@ void TouchInteraction::interpret(const std::vector& list, const std: // Calculate how much interpreted interaction should change the camera state (based on _vel) void TouchInteraction::accelerate(const std::vector& list, const std::vector& lastProcessed) { TuioCursor cursor = list.at(0); - if (!_action.rot || !_action.pick) { + if (_action != ROT || _action != PICK) { _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); } - if (_action.rot) { // add rotation velocity - _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; - } - if (_action.pinch) { // add zooming velocity - double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { - return d + c.getDistance(_centroid.x, _centroid.y); - }); - double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { - return d + p.second.getDistance(_centroid.x, _centroid.y); - }); - - double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); // make into log space instead - - _vel.zoom += zoomFactor * _sensitivity.zoom; - } - if (_action.pan) { // add local rotation velocity - _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; - } - if (_action.roll) { // add global roll rotation velocity - double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { - TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; - double res = diff; - double lastAngle = point.getAngle(_centroid.x, _centroid.y); - double currentAngle = c.getAngle(_centroid.x, _centroid.y); - if (lastAngle > currentAngle + 1.5 * M_PI) - res += currentAngle + (2 * M_PI - lastAngle); - else if (currentAngle > lastAngle + 1.5 * M_PI) - res += (2 * M_PI - currentAngle) + lastAngle; - else - res += currentAngle - lastAngle; - return res; - }); - _vel.localRoll += -rollFactor * _sensitivity.localRoll; - } - if (_action.pick) { // pick something in the scene as focus node - - if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { - _focusNode = _selected.at(0).node; // rotate camera to look at new focus - OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode - glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); - glm::dvec3 camUp = glm::normalize(_camera->lookUpVectorWorldSpace()); - glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); - - double angle = glm::angle(camForward, camToFocus); - glm::dvec3 axis = glm::normalize(glm::cross(camForward, camToFocus)); - _toSlerp.x = axis.x * sin(angle / 2.0); - _toSlerp.y = axis.y * sin(angle / 2.0); - _toSlerp.z = axis.z * sin(angle / 2.0); - _toSlerp.w = cos(angle / 2.0); - _time = 0.0; + switch (_action) { + case ROT: { // add rotation velocity + _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; + break; } - else { // should zoom in to current _selected.coordinates position but not further than _directTouchMode activation - double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); - double startDecline = _focusNode->boundingSphere() / (0.15 * _projectionScaleFactor); - double factor = 2.0; - if (dist < startDecline) { - factor = 1.0 + std::pow(dist / startDecline, 2); + case PINCH: { // add zooming velocity + double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { + return d + c.getDistance(_centroid.x, _centroid.y); + }); + double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { + return d + p.second.getDistance(_centroid.x, _centroid.y); + }); + + double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); // make into log space instead + _vel.zoom += zoomFactor * _sensitivity.zoom; + break; + } + case ROLL: { // add global roll rotation velocity + double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { + TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; + double res = diff; + double lastAngle = point.getAngle(_centroid.x, _centroid.y); + double currentAngle = c.getAngle(_centroid.x, _centroid.y); + if (lastAngle > currentAngle + 1.5 * M_PI) + res += currentAngle + (2 * M_PI - lastAngle); + else if (currentAngle > lastAngle + 1.5 * M_PI) + res += (2 * M_PI - currentAngle) + lastAngle; + else + res += currentAngle - lastAngle; + return res; + }); + _vel.localRoll += -rollFactor * _sensitivity.localRoll; + break; + } + case PAN: { // add local rotation velocity + _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; + break; + } + case PICK: { // pick something in the scene as focus node + if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { + _focusNode = _selected.at(0).node; // rotate camera to look at new focus + OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode + glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); + glm::dvec3 camUp = glm::normalize(_camera->lookUpVectorWorldSpace()); + glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); + + double angle = glm::angle(camForward, camToFocus); + glm::dvec3 axis = glm::normalize(glm::cross(camForward, camToFocus)); + _toSlerp.x = axis.x * sin(angle / 2.0); + _toSlerp.y = axis.y * sin(angle / 2.0); + _toSlerp.z = axis.z * sin(angle / 2.0); + _toSlerp.w = cos(angle / 2.0); + _time = 0.0; } - double response = _focusNode->boundingSphere() / (factor * _currentRadius * _projectionScaleFactor); - _vel.zoom = _sensitivity.zoom * response; + else { // should zoom in to current but not too much + double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); + double startDecline = _focusNode->boundingSphere() / (0.15 * _projectionScaleFactor); + double factor = 2.0; + if (dist < startDecline) { + factor = 1.0 + std::pow(dist / startDecline, 2); + } + double response = _focusNode->boundingSphere() / (factor * _currentRadius * _projectionScaleFactor); + _vel.zoom = _sensitivity.zoom * response; + } + break; } - } } @@ -480,11 +464,8 @@ void TouchInteraction::step(double dt) { dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); - double boundingSphere = _focusNode->boundingSphere(); - double minHeightAboveBoundingSphere = 1; dvec3 centerToBoundingSphere; - double distance = std::max(length(centerToCamera) - boundingSphere, 0.0); _currentRadius = boundingSphere / std::max(distance * _projectionScaleFactor, 1.0); @@ -499,7 +480,7 @@ void TouchInteraction::step(double dt) { // if we have chosen a new focus node if (_time < 1) { - _time += 0.5 * dt; + _time += 0.25 * dt; localCamRot = slerp(localCamRot, _toSlerp, _time); } } @@ -523,22 +504,19 @@ void TouchInteraction::step(double dt) { { // Zooming centerToBoundingSphere = -directionToCenter * boundingSphere; dvec3 centerToCamera = camPos - centerPos; - if (length(_vel.zoom*dt) < length(centerToCamera - centerToBoundingSphere) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) // should get boundingsphere from focusnode - camPos += directionToCenter*_vel.zoom*dt; - else - _vel.zoom = 0.0; + double distToSurface = length(centerToCamera - centerToBoundingSphere); + + if (_directTouchMode) { + camPos += directionToCenter * _vel.zoom * dt; + } + else if (length(_vel.zoom*dt) < (distToSurface / 2) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) { + camPos += directionToCenter * _vel.zoom * dt; + } } - { // Roll around sphere normal + { // Roll around sphere normal - is this something we ever want to do? dquat camRollRot = angleAxis(_vel.globalRoll*dt, -directionToCenter); globalCamRot = camRollRot * globalCamRot; } - if (!_directTouchMode) { // Push up to surface - dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere); - double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera); - camPos += -directionToCenter * max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); - - configSensitivities(length(camPos - (centerPos + centerToBoundingSphere))); // might not be needed when direct touch is active - } decelerate(); // Update the camera state @@ -547,34 +525,6 @@ void TouchInteraction::step(double dt) { } } -// Might not be needed with direct-manipulation -void TouchInteraction::configSensitivities(double dist) { - // Configurates sensitivities to appropriate values when the camera is close to the focus node. - std::shared_ptr gbim = - std::dynamic_pointer_cast (OsEng.interactionHandler().interactionmode()); - double close = 4.6 * 1000000; - if (gbim && dist < close) { - _sensitivity.zoom = 2.0 * std::max(dist, 100.0)/close; - _sensitivity.globalRot = 0.1 * std::max(dist, 100.0) /close; - //_sensitivity.localRot = 0.1; - //_sensitivity.globalRoll = 0.1; - //_sensitivity.localRoll = 0.1; - } - else if (dist < close) { - _sensitivity.zoom = 2.0 * std::max(dist, 100.0) / close; - _sensitivity.globalRot = 0.1 * std::max(dist, 100.0) / close; - } - else { - _sensitivity.zoom = 2.0; - _sensitivity.globalRot = 0.1; - _sensitivity.localRot = 0.1; - _sensitivity.globalRoll = 0.1; - _sensitivity.localRoll = 0.2; - } - - -} - void TouchInteraction::decelerate() { if (_directTouchMode) { _vel.globalRot = glm::dvec2(0.0, 0.0); @@ -582,20 +532,16 @@ void TouchInteraction::decelerate() { _vel.localRoll = 0.0; _vel.localRot = glm::dvec2(0.0, 0.0); } - _vel.zoom *= (1 - _friction.zoom); - _vel.globalRot *= (1 - _friction.globalRot); - _vel.localRot *= (1 - _friction.localRot); - _vel.globalRoll *= (1 - _friction.globalRoll); - _vel.localRoll *= (1 - _friction.localRoll); + else { + _vel.zoom *= (1 - _friction.zoom); + _vel.globalRot *= (1 - _friction.globalRot); + _vel.localRot *= (1 - _friction.localRot); + _vel.globalRoll *= (1 - _friction.globalRoll); + _vel.localRoll *= (1 - _friction.localRoll); + } } void TouchInteraction::clear() { - _action.rot = false; - _action.pinch = false; - _action.pan = false; - _action.roll = false; - _action.pick = false; - //_directTouchMode = false; _selected.clear(); // should clear if no longer have a direct-touch input } @@ -604,29 +550,17 @@ void TouchInteraction::tap() { _tap = true; } -// Getters +// Get & Setters Camera* TouchInteraction::getCamera() { return _camera; } SceneGraphNode* TouchInteraction::getFocusNode() { return _focusNode; } -double TouchInteraction::getFriction() { - return _baseFriction; -} -double TouchInteraction::getSensitivity() { - return _baseSensitivity; -} -// Setters void TouchInteraction::setCamera(Camera* camera) { _camera = camera; } void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { _focusNode = focusNode; } -void TouchInteraction::setFriction(double friction) { - _baseFriction = std::max(friction, 0.0); -} -void TouchInteraction::setSensitivity(double sensitivity) { - _baseSensitivity = sensitivity; -} + diff --git a/openspace.cfg b/openspace.cfg index 6790350464..cf331c42ce 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -26,7 +26,7 @@ return { -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/default.scene", + Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/globebrowsing.scene", -- Scene = "${SCENE}/rosetta.scene", -- Scene = "${SCENE}/dawn.scene", From c54f485b0d5d7f91ff638174091822062f00d9cb Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 27 Apr 2017 14:03:33 -0600 Subject: [PATCH 074/192] first pass on scaling _sensitivities with screen size --- modules/touch/include/TouchInteraction.h | 13 ++++---- modules/touch/src/TouchInteraction.cpp | 40 ++++++++++++++---------- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 37d266b460..2806e7abc8 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -58,15 +58,15 @@ struct VelocityStates { double zoom; glm::dvec2 globalRot; glm::dvec2 localRot; - double globalRoll; - double localRoll; + double globalRoll; // never used + double localRoll; }; struct ScaleFactor { double zoom; double globalRot; - double localRot; - double globalRoll; - double localRoll; + double localRot; // pan + double globalRoll; // never used + double localRoll; // roll }; struct SelectedBody { int id; @@ -121,6 +121,7 @@ class TouchInteraction : public properties::PropertyOwner SceneGraphNode* _focusNode = nullptr; properties::StringProperty _origin; + properties::FloatProperty _touchScreenSize; VelocityStates _vel; ScaleFactor _friction; ScaleFactor _sensitivity; @@ -131,7 +132,7 @@ class TouchInteraction : public properties::PropertyOwner double _time; bool _directTouchMode; bool _tap; - properties::Vec2Property _touchScreenSize; + std::vector _selected; LMstat _lmstat; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index ca599ed8cb..6648345404 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -57,16 +57,15 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), + _touchScreenSize("TouchScreenSize", "Normalizes _sensitivity with screen size given in inches.", 55.0f, 5.5f, 150.0f), // (5.5f) for iphone 6s plus, 4.7f smaller _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, - _friction{ 0.02, 0.01, 0.02, 0.02, 0.02 }, - _sensitivity{ 2.0, 0.1, 0.1, 0.1, 0.4 }, + _friction{ 0.02, 0.01, 0.02, 1, 0.02 }, + _sensitivity{ 2.0 * 55.0, 0.1, 0.1, 1, 0.4 * 55.0 }, _centroid{ glm::dvec3(0.0) }, _action{ -1 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _currentRadius{ 1.0 }, _time{ 1.0 }, - _directTouchMode{ false }, _tap{ false }, - _touchScreenSize("TouchScreenSize", "Touch Screen Normalizer", glm::vec2(122, 68), glm::vec2(0), glm::vec2(1000)) - // glm::vec2(width, height) in cm. (13.81, 6.7) for iphone 6s plus + _directTouchMode{ false }, _tap{ false } { addProperty(_touchScreenSize); levmarq_init(&_lmstat); @@ -93,6 +92,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition _directTouchMode = true; } @@ -344,6 +344,7 @@ int TouchInteraction::interpret(const std::vector& list, const std:: id = c.getSessionID(); } } + if (_tap) { _tap = false; return PICK; @@ -352,7 +353,7 @@ int TouchInteraction::interpret(const std::vector& list, const std:: return ROT; } else { - if (std::abs(dist - lastDist)/list.at(0).getMotionSpeed() < 0.01 && list.size() == 3) { // if distance between fingers is constant we have panning + if (std::abs(dist - lastDist) / list.at(0).getMotionSpeed() < 0.01 && list.size() == 3) { // if distance between fingers is constant we have panning return PAN; } else if (list.size() > 1 && std::abs(minDiff) < 0.0008) { // if one finger is 'still' (0.0008 works as epsilon) and another moving, we have roll @@ -385,8 +386,8 @@ void TouchInteraction::accelerate(const std::vector& list, const std return d + p.second.getDistance(_centroid.x, _centroid.y); }); - double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); // make into log space instead - _vel.zoom += zoomFactor * _sensitivity.zoom; + double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); + _vel.zoom += zoomFactor * _sensitivity.zoom / _touchScreenSize.value(); break; } case ROLL: { // add global roll rotation velocity @@ -403,7 +404,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std res += currentAngle - lastAngle; return res; }); - _vel.localRoll += -rollFactor * _sensitivity.localRoll; + _vel.localRoll += -rollFactor * _sensitivity.localRoll / _touchScreenSize.value(); // _sensitivity could be 0.4 = x * (_touchScreenSize.value().x * _touchScreenSize.value().y) break; } case PAN: { // add local rotation velocity @@ -412,15 +413,13 @@ void TouchInteraction::accelerate(const std::vector& list, const std } case PICK: { // pick something in the scene as focus node if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { - _focusNode = _selected.at(0).node; // rotate camera to look at new focus + setFocusNode(_selected.at(0).node); OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); - glm::dvec3 camUp = glm::normalize(_camera->lookUpVectorWorldSpace()); glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); - double angle = glm::angle(camForward, camToFocus); glm::dvec3 axis = glm::normalize(glm::cross(camForward, camToFocus)); - _toSlerp.x = axis.x * sin(angle / 2.0); + _toSlerp.x = axis.x * sin(angle / 2.0); // rotate camera to look at new focus _toSlerp.y = axis.y * sin(angle / 2.0); _toSlerp.z = axis.z * sin(angle / 2.0); _toSlerp.w = cos(angle / 2.0); @@ -430,11 +429,11 @@ void TouchInteraction::accelerate(const std::vector& list, const std double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); double startDecline = _focusNode->boundingSphere() / (0.15 * _projectionScaleFactor); double factor = 2.0; - if (dist < startDecline) { + if (dist < startDecline) { // double-check this factor = 1.0 + std::pow(dist / startDecline, 2); } double response = _focusNode->boundingSphere() / (factor * _currentRadius * _projectionScaleFactor); - _vel.zoom = _sensitivity.zoom * response; + _vel.zoom = (_sensitivity.zoom / 55) * response; // _sensitivity could be 2.0 = x * (_touchScreenSize.value().x * _touchScreenSize.value().y) } break; } @@ -468,6 +467,10 @@ void TouchInteraction::step(double dt) { dvec3 centerToBoundingSphere; double distance = std::max(length(centerToCamera) - boundingSphere, 0.0); _currentRadius = boundingSphere / std::max(distance * _projectionScaleFactor, 1.0); + + /*if (!_directTouchMode && _currentRadius > 0.3) { + _vel.zoom *= _friction.zoom; + }*/ { // Roll dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); @@ -509,9 +512,12 @@ void TouchInteraction::step(double dt) { if (_directTouchMode) { camPos += directionToCenter * _vel.zoom * dt; } - else if (length(_vel.zoom*dt) < (distToSurface / 2) && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) { + else if (length(_vel.zoom*dt) < distToSurface && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) { camPos += directionToCenter * _vel.zoom * dt; } + else { + _vel.zoom = 0.0; + } } { // Roll around sphere normal - is this something we ever want to do? dquat camRollRot = angleAxis(_vel.globalRoll*dt, -directionToCenter); @@ -525,6 +531,7 @@ void TouchInteraction::step(double dt) { } } +// Decelerate velocities (set 0 for directTouch) void TouchInteraction::decelerate() { if (_directTouchMode) { _vel.globalRot = glm::dvec2(0.0, 0.0); @@ -541,6 +548,7 @@ void TouchInteraction::decelerate() { } } +// Called if all fingers are off the screen void TouchInteraction::clear() { //_directTouchMode = false; _selected.clear(); // should clear if no longer have a direct-touch input From bbe99f1a11350623a4b0d72199d48805d8c409cc Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 27 Apr 2017 14:32:35 -0600 Subject: [PATCH 075/192] fix misinterpreted taps --- modules/touch/src/TouchInteraction.cpp | 17 ++++++++--------- modules/touch/src/TuioEar.cpp | 6 +++--- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 6648345404..cd2819fac5 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -57,7 +57,7 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), - _touchScreenSize("TouchScreenSize", "Normalizes _sensitivity with screen size given in inches.", 55.0f, 5.5f, 150.0f), // (5.5f) for iphone 6s plus, 4.7f smaller + _touchScreenSize("TouchScreenSize", "Normalizes _sensitivity with screen size given in inches.", 55.0f, 5.5f, 150.0f), _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ 0.02, 0.01, 0.02, 1, 0.02 }, _sensitivity{ 2.0 * 55.0, 0.1, 0.1, 1, 0.4 * 55.0 }, @@ -404,7 +404,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std res += currentAngle - lastAngle; return res; }); - _vel.localRoll += -rollFactor * _sensitivity.localRoll / _touchScreenSize.value(); // _sensitivity could be 0.4 = x * (_touchScreenSize.value().x * _touchScreenSize.value().y) + _vel.localRoll += -rollFactor * _sensitivity.localRoll / _touchScreenSize.value(); break; } case PAN: { // add local rotation velocity @@ -433,7 +433,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std factor = 1.0 + std::pow(dist / startDecline, 2); } double response = _focusNode->boundingSphere() / (factor * _currentRadius * _projectionScaleFactor); - _vel.zoom = (_sensitivity.zoom / 55) * response; // _sensitivity could be 2.0 = x * (_touchScreenSize.value().x * _touchScreenSize.value().y) + _vel.zoom = (_sensitivity.zoom / 55) * response; } break; } @@ -467,10 +467,6 @@ void TouchInteraction::step(double dt) { dvec3 centerToBoundingSphere; double distance = std::max(length(centerToCamera) - boundingSphere, 0.0); _currentRadius = boundingSphere / std::max(distance * _projectionScaleFactor, 1.0); - - /*if (!_directTouchMode && _currentRadius > 0.3) { - _vel.zoom *= _friction.zoom; - }*/ { // Roll dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); @@ -509,10 +505,10 @@ void TouchInteraction::step(double dt) { dvec3 centerToCamera = camPos - centerPos; double distToSurface = length(centerToCamera - centerToBoundingSphere); - if (_directTouchMode) { + if (length(_vel.zoom*dt) < distToSurface && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) { camPos += directionToCenter * _vel.zoom * dt; } - else if (length(_vel.zoom*dt) < distToSurface && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) { + else if (_directTouchMode) { camPos += directionToCenter * _vel.zoom * dt; } else { @@ -540,6 +536,9 @@ void TouchInteraction::decelerate() { _vel.localRot = glm::dvec2(0.0, 0.0); } else { + if (!_directTouchMode && _currentRadius > 0.3) { + _vel.zoom *= (1 - 2*_friction.zoom); + } _vel.zoom *= (1 - _friction.zoom); _vel.globalRot *= (1 - _friction.globalRot); _vel.localRot *= (1 - _friction.localRot); diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index d04a2c3638..c66b0d8c6a 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -88,12 +88,12 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { // save id to be removed and remove it in clearInput void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); - if (tcur->getPath().size() < 4 && tcur->getMotionSpeed() < 0.03) { + _removeList.push_back(tcur->getSessionID()); + + if (tcur->getPath().size() < 4 && tcur->getMotionSpeed() < 0.03 && _list.size() == _removeList.size() == 1) { _tapCo = TuioCursor(*tcur); _tap = true; } - - _removeList.push_back(tcur->getSessionID()); _mx.unlock(); } From 11c2d063c0fa254cc8d52c8e9874afc60680d1d0 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 27 Apr 2017 15:49:34 -0600 Subject: [PATCH 076/192] decrease velocity as we get closer to the planet more smoothly, fixed 'lose-focusnode'-bug with direct touch --- modules/touch/src/TouchInteraction.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index cd2819fac5..b76ce07179 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -508,9 +508,6 @@ void TouchInteraction::step(double dt) { if (length(_vel.zoom*dt) < distToSurface && length(centerToCamera + directionToCenter*_vel.zoom*dt) > length(centerToBoundingSphere)) { camPos += directionToCenter * _vel.zoom * dt; } - else if (_directTouchMode) { - camPos += directionToCenter * _vel.zoom * dt; - } else { _vel.zoom = 0.0; } @@ -536,7 +533,7 @@ void TouchInteraction::decelerate() { _vel.localRot = glm::dvec2(0.0, 0.0); } else { - if (!_directTouchMode && _currentRadius > 0.3) { + if (!_directTouchMode && _currentRadius > 0.3 && _vel.zoom > _focusNode->boundingSphere()) { // check for velocity speed too _vel.zoom *= (1 - 2*_friction.zoom); } _vel.zoom *= (1 - _friction.zoom); From 8f36159cba8e3bb4c0afc69346a81f8245889e21 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 2 May 2017 15:24:42 -0600 Subject: [PATCH 077/192] add prints of gradient if verbose --- modules/touch/ext/levmarq.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index a36a0605ca..3b7997a29e 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -144,6 +144,13 @@ bool levmarq(int npar, double *par, int ny, double *dysq, lmstat->final_err = err; lmstat->final_derr = derr; + if (verbose) { + for (int i = 0; i < npar; ++i) { + printf("g[%d] = %g, ", i, g[i]); + } + printf("\n"); + } + // deallocate the arrays for (int i = 0; i < npar; i++) { delete[] h[i]; From 7f7b40d736e83941e9d693880bcc684e900c1a24 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 2 May 2017 15:25:22 -0600 Subject: [PATCH 078/192] solve snapping bug by not overwriting selected surface coordinates in case levmarq doesn't converge. --- modules/touch/include/TouchInteraction.h | 1 + modules/touch/src/TouchInteraction.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 2806e7abc8..d21c889b76 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -132,6 +132,7 @@ class TouchInteraction : public properties::PropertyOwner double _time; bool _directTouchMode; bool _tap; + bool _levSuccess; std::vector _selected; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index b76ce07179..e42bed3677 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -65,7 +65,7 @@ TouchInteraction::TouchInteraction() _action{ -1 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _currentRadius{ 1.0 }, _time{ 1.0 }, - _directTouchMode{ false }, _tap{ false } + _directTouchMode{ false }, _tap{ false }, _levSuccess{ true } { addProperty(_touchScreenSize); levmarq_init(&_lmstat); @@ -86,7 +86,8 @@ void TouchInteraction::update(const std::vector& list, std::vector

0 && list.size() == _selected.size()) { manipulate(list); } - trace(list); + if (_levSuccess) + trace(list); if (!_directTouchMode) { _action = interpret(list, lastProcessed); accelerate(list, lastProcessed); @@ -190,7 +191,7 @@ void TouchInteraction::manipulate(const std::vector& list) { f1 = ptr->distToMinimize(dPar, x, fdata); dPar[i] -= h; der = (f1 - f0) / h; - + g[i] = (i > 1 && i < 4) ? der : der / abs(der); } delete[] dPar; @@ -241,11 +242,11 @@ void TouchInteraction::manipulate(const std::vector& list) { } // debugging - /*std::ostringstream os; + std::ostringstream os; for (int i = 0; i < nDOF; ++i) { os << par[i] << ", "; } - std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ + std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n"; // cleanup delete[] par; @@ -547,6 +548,7 @@ void TouchInteraction::decelerate() { // Called if all fingers are off the screen void TouchInteraction::clear() { //_directTouchMode = false; + _levSuccess = true; _selected.clear(); // should clear if no longer have a direct-touch input } From f3bf3fb5c7b2067d0921d9f3f5dd9d0cda47071e Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 2 May 2017 16:08:01 -0600 Subject: [PATCH 079/192] start of guiMode implementation --- modules/touch/include/TouchInteraction.h | 4 +- modules/touch/src/TouchInteraction.cpp | 65 ++++++++++++++---------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index d21c889b76..4215bdb06b 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -109,6 +109,7 @@ class TouchInteraction : public properties::PropertyOwner void decelerate(); void clear(); void tap(); + bool guiON(); // Get & Setters Camera* getCamera(); @@ -125,14 +126,13 @@ class TouchInteraction : public properties::PropertyOwner VelocityStates _vel; ScaleFactor _friction; ScaleFactor _sensitivity; - glm::dvec3 _centroid; - int _action; double _projectionScaleFactor; double _currentRadius; double _time; bool _directTouchMode; bool _tap; bool _levSuccess; + bool _guiON; std::vector _selected; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index e42bed3677..91da3d03ff 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -61,11 +61,9 @@ TouchInteraction::TouchInteraction() _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, _friction{ 0.02, 0.01, 0.02, 1, 0.02 }, _sensitivity{ 2.0 * 55.0, 0.1, 0.1, 1, 0.4 * 55.0 }, - _centroid{ glm::dvec3(0.0) }, - _action{ -1 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _currentRadius{ 1.0 }, _time{ 1.0 }, - _directTouchMode{ false }, _tap{ false }, _levSuccess{ true } + _directTouchMode{ false }, _tap{ false }, _levSuccess{ true }, _guiON{ false } { addProperty(_touchScreenSize); levmarq_init(&_lmstat); @@ -83,22 +81,29 @@ TouchInteraction::~TouchInteraction() { } // Called each frame if there is any input void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { - manipulate(list); + // check if tapped in corner to activate gui mode + glm::dvec2 pos = glm::dvec2(list.at(0).getX(), list.at(0).getY()); + if (_tap && list.size() == 1 && pos.x < 0.0001 && pos.y < 0.0001 /*|| check if showGUI*/) { + // if !showGUI press F1, + _guiON = !_guiON; } - if (_levSuccess) - trace(list); - if (!_directTouchMode) { - _action = interpret(list, lastProcessed); - accelerate(list, lastProcessed); - } - - // evaluates if current frame is in directTouchMode (will if so be used next frame) - if (_currentRadius > 0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition - _directTouchMode = true; - } - else { - _directTouchMode = false; + else if (!_guiON) { + if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { + manipulate(list); + } + if (_levSuccess) + trace(list); + if (!_directTouchMode) { + accelerate(list, lastProcessed); + } + + // evaluates if current frame is in directTouchMode (will if so be used next frame) + if (_currentRadius > 0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition + _directTouchMode = true; + } + else { + _directTouchMode = false; + } } } @@ -363,28 +368,31 @@ int TouchInteraction::interpret(const std::vector& list, const std:: else { return PINCH; } - } + } } // Calculate how much interpreted interaction should change the camera state (based on _vel) void TouchInteraction::accelerate(const std::vector& list, const std::vector& lastProcessed) { TuioCursor cursor = list.at(0); - if (_action != ROT || _action != PICK) { - _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); - _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + glm::dvec3 centroid; + int action = interpret(list, lastProcessed); + + if (action != ROT || action != PICK) { + centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); } - switch (_action) { + switch (action) { case ROT: { // add rotation velocity _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; break; } case PINCH: { // add zooming velocity double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { - return d + c.getDistance(_centroid.x, _centroid.y); + return d + c.getDistance(centroid.x, centroid.y); }); double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { - return d + p.second.getDistance(_centroid.x, _centroid.y); + return d + p.second.getDistance(centroid.x, centroid.y); }); double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); @@ -395,8 +403,8 @@ void TouchInteraction::accelerate(const std::vector& list, const std double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = diff; - double lastAngle = point.getAngle(_centroid.x, _centroid.y); - double currentAngle = c.getAngle(_centroid.x, _centroid.y); + double lastAngle = point.getAngle(centroid.x, centroid.y); + double currentAngle = c.getAngle(centroid.x, centroid.y); if (lastAngle > currentAngle + 1.5 * M_PI) res += currentAngle + (2 * M_PI - lastAngle); else if (currentAngle > lastAngle + 1.5 * M_PI) @@ -556,6 +564,9 @@ void TouchInteraction::tap() { _tap = true; } +bool TouchInteraction::guiON() { + return _guiON; +} // Get & Setters Camera* TouchInteraction::getCamera() { return _camera; From 824cd1be053a3127bae8b7b7e7642cb105d32dc3 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 4 May 2017 17:29:30 -0600 Subject: [PATCH 080/192] guiMode infrastructure, just need to emulate mouse correctly --- modules/touch/include/TouchInteraction.h | 2 +- modules/touch/src/TouchInteraction.cpp | 77 +++++++++++++++++------- modules/touch/src/TuioEar.cpp | 4 +- openspace.cfg | 4 +- 4 files changed, 60 insertions(+), 27 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 4215bdb06b..7bc9479467 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -99,6 +99,7 @@ class TouchInteraction : public properties::PropertyOwner ~TouchInteraction(); void update(const std::vector& list, std::vector& lastProcessed); + bool gui(const std::vector& list); void manipulate(const std::vector& list); void trace(const std::vector& list); int interpret(const std::vector& list, const std::vector& lastProcessed); @@ -109,7 +110,6 @@ class TouchInteraction : public properties::PropertyOwner void decelerate(); void clear(); void tap(); - bool guiON(); // Get & Setters Camera* getCamera(); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 91da3d03ff..96eb96924d 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -24,6 +24,7 @@ #include +#include #include #include @@ -82,17 +83,14 @@ TouchInteraction::~TouchInteraction() { } // Called each frame if there is any input void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { // check if tapped in corner to activate gui mode - glm::dvec2 pos = glm::dvec2(list.at(0).getX(), list.at(0).getY()); - if (_tap && list.size() == 1 && pos.x < 0.0001 && pos.y < 0.0001 /*|| check if showGUI*/) { - // if !showGUI press F1, - _guiON = !_guiON; - } - else if (!_guiON) { + + if (!gui(list)) { if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { manipulate(list); } - if (_levSuccess) + if (_levSuccess) { trace(list); + } if (!_directTouchMode) { accelerate(list, lastProcessed); } @@ -107,6 +105,40 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list) { + WindowWrapper& wrapper = OsEng.windowWrapper(); + bool showGui = wrapper.hasGuiWindow() ? wrapper.isGuiWindow() : true; + glm::ivec2 res = wrapper.currentWindowSize(); + glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenX(res.y)); // mouse pixel position + glm::vec2 button = glm::vec2(36, 64); // pixel size + if (_tap && list.size() == 1 && pos.x < button.x && pos.y < button.y) { // pressed invisible button + _tap = false; + _guiON = !_guiON; + OnScreenGUIModule::gui.setEnabled(_guiON); + + std::string mode = (_guiON) ? "" : "de"; + LINFO("GUI mode is " << mode << "activated. Inside box by: (" << + static_cast(100 * (pos.x / button.x)) << "%, " << static_cast(100 * (pos.y / button.y)) << "%)\n"); + } + else if (_guiON) { // emulate mouse + int action = (_tap) ? 0 : 1; + LINFO("Pos: " << glm::to_string(pos) << ", Button: " << action << "_tap: " << _tap << "\n"); + interaction::InputState().mousePositionCallback(pos.x, pos.y); + interaction::InputState().mouseButtonCallback(openspace::MouseButton(0), openspace::MouseAction(action)); + + double dt = std::max(wrapper.averageDeltaTime(), 0.0); + OnScreenGUIModule::gui.startFrame(static_cast(dt), + wrapper.currentWindowSize(), + wrapper.dpiScaling(), + pos, + action); + OnScreenGUIModule::gui.endFrame(); + + + } + return _guiON; +} + // Sets _vel to update _camera according to direct-manipulation (L2 error) void TouchInteraction::manipulate(const std::vector& list) { // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi @@ -205,7 +237,7 @@ void TouchInteraction::manipulate(const std::vector& list) { SceneGraphNode* node = _selected.at(0).node; auto castToNDC = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node, double aspectRatio) { glm::dvec3 backToScreenSpace = glm::inverse(camera.rotationQuaternion()) - * glm::normalize(((node->rotationMatrix() * vec) + node->worldPosition() - camera.positionVec3())); + * glm::normalize(((node->rotationMatrix() * vec) + (node->worldPosition() - camera.positionVec3()) )); backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); backToScreenSpace.x /= aspectRatio; @@ -228,8 +260,8 @@ void TouchInteraction::manipulate(const std::vector& list) { double yCo = -2 * (c->getY() - 0.5); // normalized -1 to 1 coordinates on screen screenPoints.push_back(glm::dvec2(xCo, yCo)); } - glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, res.x / res.y }; + //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88 }; void* dataPtr = reinterpret_cast(&fData); bool success = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par @@ -247,11 +279,11 @@ void TouchInteraction::manipulate(const std::vector& list) { } // debugging - std::ostringstream os; + /*std::ostringstream os; for (int i = 0; i < nDOF; ++i) { os << par[i] << ", "; } - std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n"; + std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ // cleanup delete[] par; @@ -270,8 +302,8 @@ void TouchInteraction::trace(const std::vector& list) { if (node->name() == name) selectableNodes.push_back(node); - glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - double aspectRatio = res.x/res.y; + //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + double aspectRatio = 1.88; //res.x/res.y; glm::dquat camToWorldSpace = _camera->rotationQuaternion(); glm::dvec3 camPos = _camera->positionVec3(); std::vector newSelected; @@ -280,6 +312,8 @@ void TouchInteraction::trace(const std::vector& list) { double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -3.2596558); glm::dvec3 raytrace = glm::normalize(cursorInWorldSpace); + + int id = c.getSessionID(); for (SceneGraphNode* node : selectableNodes) { double boundingSphere = node->boundingSphere(); @@ -293,9 +327,8 @@ void TouchInteraction::trace(const std::vector& list) { d -= sqrt(root); glm::dvec3 intersectionPoint = camPos + d * raytrace; glm::dvec3 pointInModelView = glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition()); - // spherical coordinates for point on surface, maybe not required - double theta = atan(pointInModelView.y / pointInModelView.x); - double phi = atan(glm::length(glm::dvec2(pointInModelView.x, pointInModelView.y)) / pointInModelView.z); + //double theta = atan(pointInModelView.y / pointInModelView.x); + //double phi = atan(glm::length(glm::dvec2(pointInModelView.x, pointInModelView.y)) / pointInModelView.z); // Add id, node and surface coordinates to the selected list std::vector::iterator oldNode = find_if(newSelected.begin(), newSelected.end(), [id](SelectedBody s) { return s.id == id; }); @@ -313,12 +346,12 @@ void TouchInteraction::trace(const std::vector& list) { } } + _selected = newSelected; + //debugging for (auto it : newSelected) { //std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; } - - _selected = newSelected; } // Interprets the input gesture to a specific interaction @@ -530,6 +563,8 @@ void TouchInteraction::step(double dt) { // Update the camera state _camera->setPositionVec3(camPos); _camera->setRotation(globalCamRot * localCamRot); + + _tap = false; } } @@ -556,6 +591,7 @@ void TouchInteraction::decelerate() { // Called if all fingers are off the screen void TouchInteraction::clear() { //_directTouchMode = false; + //_tap = false; _levSuccess = true; _selected.clear(); // should clear if no longer have a direct-touch input } @@ -564,9 +600,6 @@ void TouchInteraction::tap() { _tap = true; } -bool TouchInteraction::guiON() { - return _guiON; -} // Get & Setters Camera* TouchInteraction::getCamera() { return _camera; diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index c66b0d8c6a..abc6f93748 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -89,8 +89,7 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); _removeList.push_back(tcur->getSessionID()); - - if (tcur->getPath().size() < 4 && tcur->getMotionSpeed() < 0.03 && _list.size() == _removeList.size() == 1) { + if (tcur->getPath().size() < 4 && tcur->getMotionSpeed() < 0.03 && _list.size() == _removeList.size() == 1) { // maybe take away motionspeed _tapCo = TuioCursor(*tcur); _tap = true; } @@ -121,6 +120,7 @@ bool TuioEar::tap() { } TuioCursor TuioEar::getTap() { + std::lock_guard lock(_mx); return _tapCo; } diff --git a/openspace.cfg b/openspace.cfg index cf331c42ce..08f6ef36e1 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,13 +7,13 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, + --SGCTConfig = sgct.config.single{}, -- Fullscreen mode --SGCTConfig = sgct.config.single{fullScreen=true}, -- A regular 1920x1080 window - -- SGCTConfig = sgct.config.single{1920, 1080, border=false}, + SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From 7580688f88216de730a0b107beea645b615ef94e Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 5 May 2017 14:00:12 -0600 Subject: [PATCH 081/192] modification to allow gui control through touch --- modules/onscreengui/onscreenguimodule.cpp | 6 +++++- modules/onscreengui/onscreenguimodule.h | 9 ++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/modules/onscreengui/onscreenguimodule.cpp b/modules/onscreengui/onscreenguimodule.cpp index c4096e8726..83bc00f106 100644 --- a/modules/onscreengui/onscreenguimodule.cpp +++ b/modules/onscreengui/onscreenguimodule.cpp @@ -42,6 +42,7 @@ namespace openspace { gui::GUI OnScreenGUIModule::gui; +Touch OnScreenGUIModule::touchInput; OnScreenGUIModule::OnScreenGUIModule() : OpenSpaceModule("OnScreenGUI") @@ -135,7 +136,10 @@ OnScreenGUIModule::OnScreenGUIModule() uint32_t mouseButtons = wrapper.mouseButtons(2); double dt = std::max(wrapper.averageDeltaTime(), 0.0); - + if (touchInput.active && mouseButtons == 0) { + mouseButtons = touchInput.action; + mousePosition = touchInput.pos; + } // We don't do any collection of immediate mode user interface, so it is // fine to open and close a frame immediately gui.startFrame( diff --git a/modules/onscreengui/onscreenguimodule.h b/modules/onscreengui/onscreenguimodule.h index 6576843c68..cd94b58d28 100644 --- a/modules/onscreengui/onscreenguimodule.h +++ b/modules/onscreengui/onscreenguimodule.h @@ -30,12 +30,19 @@ #include namespace openspace { - + +struct Touch { + bool active; + glm::vec2 pos; + uint32_t action; +}; + class OnScreenGUIModule : public OpenSpaceModule { public: OnScreenGUIModule(); static gui::GUI gui; + static Touch touchInput; }; } // namespace openspace From 437550505e760700937add2027d6cfb2a5511f18 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 5 May 2017 14:08:17 -0600 Subject: [PATCH 082/192] The imgui can now be controlled by touch by emulating the mouse in '_guiON' --- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 38 +++++++++++++----------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 7bc9479467..99719c3147 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED @@ -132,7 +133,7 @@ class TouchInteraction : public properties::PropertyOwner bool _directTouchMode; bool _tap; bool _levSuccess; - bool _guiON; + properties::BoolProperty _guiON; std::vector _selected; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 96eb96924d..9d5cb5a054 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -64,9 +64,11 @@ TouchInteraction::TouchInteraction() _sensitivity{ 2.0 * 55.0, 0.1, 0.1, 1, 0.4 * 55.0 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _currentRadius{ 1.0 }, _time{ 1.0 }, - _directTouchMode{ false }, _tap{ false }, _levSuccess{ true }, _guiON{ false } + _directTouchMode{ false }, _tap{ false }, _levSuccess{ true }, + _guiON("Gui On", "Show GUI", false) { addProperty(_touchScreenSize); + addProperty(_guiON); levmarq_init(&_lmstat); _origin.onChange([this]() { SceneGraphNode* node = sceneGraphNode(_origin.value()); @@ -76,6 +78,7 @@ TouchInteraction::TouchInteraction() } setFocusNode(node); }); + OnScreenGUIModule::touchInput = { false, glm::vec2(0), 0 }; } TouchInteraction::~TouchInteraction() { } @@ -109,7 +112,7 @@ bool TouchInteraction::gui(const std::vector& list) { WindowWrapper& wrapper = OsEng.windowWrapper(); bool showGui = wrapper.hasGuiWindow() ? wrapper.isGuiWindow() : true; glm::ivec2 res = wrapper.currentWindowSize(); - glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenX(res.y)); // mouse pixel position + glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y)); // mouse pixel position glm::vec2 button = glm::vec2(36, 64); // pixel size if (_tap && list.size() == 1 && pos.x < button.x && pos.y < button.y) { // pressed invisible button _tap = false; @@ -120,23 +123,11 @@ bool TouchInteraction::gui(const std::vector& list) { LINFO("GUI mode is " << mode << "activated. Inside box by: (" << static_cast(100 * (pos.x / button.x)) << "%, " << static_cast(100 * (pos.y / button.y)) << "%)\n"); } - else if (_guiON) { // emulate mouse - int action = (_tap) ? 0 : 1; - LINFO("Pos: " << glm::to_string(pos) << ", Button: " << action << "_tap: " << _tap << "\n"); - interaction::InputState().mousePositionCallback(pos.x, pos.y); - interaction::InputState().mouseButtonCallback(openspace::MouseButton(0), openspace::MouseAction(action)); - - double dt = std::max(wrapper.averageDeltaTime(), 0.0); - OnScreenGUIModule::gui.startFrame(static_cast(dt), - wrapper.currentWindowSize(), - wrapper.dpiScaling(), - pos, - action); - OnScreenGUIModule::gui.endFrame(); - - + else if (_guiON) { + uint32_t action = (_tap) ? 0 : 1; + OnScreenGUIModule::touchInput = { _guiON, pos, action }; } - return _guiON; + return _guiON; // return if consumed } // Sets _vel to update _camera according to direct-manipulation (L2 error) @@ -593,6 +584,17 @@ void TouchInteraction::clear() { //_directTouchMode = false; //_tap = false; _levSuccess = true; + if (_guiON) { + bool activeLastFrame = false; + if (OnScreenGUIModule::touchInput.action) { + activeLastFrame = true; + } + OnScreenGUIModule::touchInput.active = false; + if (activeLastFrame) { + OnScreenGUIModule::touchInput.active = true; + OnScreenGUIModule::touchInput.action = 0; + } + } _selected.clear(); // should clear if no longer have a direct-touch input } From b312eb308df19a0846d2ba23a8a9db539ce5c719 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 5 May 2017 15:10:11 -0600 Subject: [PATCH 083/192] activate _guiON if gui is shown (F1), added doubleTap tracking (used for select node/zoom) --- modules/touch/include/TouchInteraction.h | 5 +++- modules/touch/src/TouchInteraction.cpp | 32 ++++++++++++++---------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 99719c3147..ad9a199b70 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -90,6 +90,7 @@ struct FunctionData { #define ROLL 2 #define PAN 3 #define PICK 4 +#define maxTapTime 300 using Point = std::pair; @@ -129,9 +130,11 @@ class TouchInteraction : public properties::PropertyOwner ScaleFactor _sensitivity; double _projectionScaleFactor; double _currentRadius; - double _time; + double _slerpTime; + TUIO::TuioTime _time; bool _directTouchMode; bool _tap; + bool _doubleTap; bool _levSuccess; properties::BoolProperty _guiON; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 9d5cb5a054..1b486eeea7 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -63,8 +63,8 @@ TouchInteraction::TouchInteraction() _friction{ 0.02, 0.01, 0.02, 1, 0.02 }, _sensitivity{ 2.0 * 55.0, 0.1, 0.1, 1, 0.4 * 55.0 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, _time{ 1.0 }, - _directTouchMode{ false }, _tap{ false }, _levSuccess{ true }, + _currentRadius{ 1.0 }, _slerpTime{ 1.0 }, + _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _levSuccess{ true }, _guiON("Gui On", "Show GUI", false) { addProperty(_touchScreenSize); @@ -79,13 +79,21 @@ TouchInteraction::TouchInteraction() setFocusNode(node); }); OnScreenGUIModule::touchInput = { false, glm::vec2(0), 0 }; + _time.initSession(); } TouchInteraction::~TouchInteraction() { } // Called each frame if there is any input void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { - // check if tapped in corner to activate gui mode + if (_tap) { // check for doubletap + if (_time.getSessionTime().getTotalMilliseconds() < maxTapTime) { + _doubleTap = true; + _tap = false; + } + _time.initSession(); + } + if (!gui(list)) { if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { @@ -110,12 +118,12 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list) { WindowWrapper& wrapper = OsEng.windowWrapper(); - bool showGui = wrapper.hasGuiWindow() ? wrapper.isGuiWindow() : true; glm::ivec2 res = wrapper.currentWindowSize(); glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y)); // mouse pixel position glm::vec2 button = glm::vec2(36, 64); // pixel size + _guiON = OnScreenGUIModule::gui.isEnabled(); + if (_tap && list.size() == 1 && pos.x < button.x && pos.y < button.y) { // pressed invisible button - _tap = false; _guiON = !_guiON; OnScreenGUIModule::gui.setEnabled(_guiON); @@ -375,8 +383,7 @@ int TouchInteraction::interpret(const std::vector& list, const std:: } } - if (_tap) { - _tap = false; + if (_doubleTap) { return PICK; } else if (list.size() == 1) { @@ -456,7 +463,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std _toSlerp.y = axis.y * sin(angle / 2.0); _toSlerp.z = axis.z * sin(angle / 2.0); _toSlerp.w = cos(angle / 2.0); - _time = 0.0; + _slerpTime = 0.0; } else { // should zoom in to current but not too much double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); @@ -511,9 +518,9 @@ void TouchInteraction::step(double dt) { localCamRot = localCamRot * rotationDiff; // if we have chosen a new focus node - if (_time < 1) { - _time += 0.25 * dt; - localCamRot = slerp(localCamRot, _toSlerp, _time); + if (_slerpTime < 1) { + _slerpTime += 0.25 * dt; + localCamRot = slerp(localCamRot, _toSlerp, _slerpTime); } } { // Orbit (global rotation) @@ -556,6 +563,7 @@ void TouchInteraction::step(double dt) { _camera->setRotation(globalCamRot * localCamRot); _tap = false; + _doubleTap = false; } } @@ -581,8 +589,6 @@ void TouchInteraction::decelerate() { // Called if all fingers are off the screen void TouchInteraction::clear() { - //_directTouchMode = false; - //_tap = false; _levSuccess = true; if (_guiON) { bool activeLastFrame = false; From 1ca9b144fc3499ad6470bbf257a2827fa71acf39 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 9 May 2017 13:38:04 -0600 Subject: [PATCH 084/192] allow for spinning on directTouchMode if global/local rot was big enough --- modules/touch/include/TouchInteraction.h | 4 +- modules/touch/src/TouchInteraction.cpp | 54 +++++++++++++++--------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index ad9a199b70..9cfd4922b4 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -126,6 +127,7 @@ class TouchInteraction : public properties::PropertyOwner properties::StringProperty _origin; properties::FloatProperty _touchScreenSize; VelocityStates _vel; + VelocityStates _lastVel; ScaleFactor _friction; ScaleFactor _sensitivity; double _projectionScaleFactor; @@ -135,7 +137,7 @@ class TouchInteraction : public properties::PropertyOwner bool _directTouchMode; bool _tap; bool _doubleTap; - bool _levSuccess; + bool _lmSuccess; properties::BoolProperty _guiON; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 1b486eeea7..30469409c6 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -64,7 +64,7 @@ TouchInteraction::TouchInteraction() _sensitivity{ 2.0 * 55.0, 0.1, 0.1, 1, 0.4 * 55.0 }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _currentRadius{ 1.0 }, _slerpTime{ 1.0 }, - _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _levSuccess{ true }, + _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON("Gui On", "Show GUI", false) { addProperty(_touchScreenSize); @@ -99,7 +99,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

0 && list.size() == _selected.size()) { manipulate(list); } - if (_levSuccess) { + if (_lmSuccess) { trace(list); } if (!_directTouchMode) { @@ -133,6 +133,13 @@ bool TouchInteraction::gui(const std::vector& list) { } else if (_guiON) { uint32_t action = (_tap) ? 0 : 1; + + /*for (const auto& func : _moduleCallbacks.mouseButton) { + bool consumed = func(0, action); + if (consumed) { + OnScreenGUIModule::touchInput = { _guiON, pos, action }; + } + }*/ OnScreenGUIModule::touchInput = { _guiON, pos, action }; } return _guiON; // return if consumed @@ -263,9 +270,9 @@ void TouchInteraction::manipulate(const std::vector& list) { FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88 }; void* dataPtr = reinterpret_cast(&fData); - bool success = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par + _lmSuccess = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - if (success) { // if good values were found set new camera state + if (_lmSuccess) { // if good values were found set new camera state _vel.globalRot = glm::dvec2(par[0], par[1]); if (nDOF > 2) { _vel.zoom = par[2]; @@ -275,6 +282,11 @@ void TouchInteraction::manipulate(const std::vector& list) { } } step(1); + _lastVel = _vel; + _vel.globalRot = glm::dvec2(0.0, 0.0); + _vel.zoom = 0.0; + _vel.localRoll = 0.0; + _vel.localRot = glm::dvec2(0.0, 0.0); } // debugging @@ -558,6 +570,7 @@ void TouchInteraction::step(double dt) { } decelerate(); + // Update the camera state _camera->setPositionVec3(camPos); _camera->setRotation(globalCamRot * localCamRot); @@ -569,27 +582,28 @@ void TouchInteraction::step(double dt) { // Decelerate velocities (set 0 for directTouch) void TouchInteraction::decelerate() { - if (_directTouchMode) { - _vel.globalRot = glm::dvec2(0.0, 0.0); - _vel.zoom = 0.0; - _vel.localRoll = 0.0; - _vel.localRot = glm::dvec2(0.0, 0.0); - } - else { - if (!_directTouchMode && _currentRadius > 0.3 && _vel.zoom > _focusNode->boundingSphere()) { // check for velocity speed too - _vel.zoom *= (1 - 2*_friction.zoom); - } - _vel.zoom *= (1 - _friction.zoom); - _vel.globalRot *= (1 - _friction.globalRot); - _vel.localRot *= (1 - _friction.localRot); - _vel.globalRoll *= (1 - _friction.globalRoll); - _vel.localRoll *= (1 - _friction.localRoll); + if (!_directTouchMode && _currentRadius > 0.3 && _vel.zoom > _focusNode->boundingSphere()) { // check for velocity speed too + _vel.zoom *= (1 - 2*_friction.zoom); } + _vel.zoom *= (1 - _friction.zoom); + _vel.globalRot *= (1 - _friction.globalRot); + _vel.localRot *= (1 - _friction.localRot); + _vel.globalRoll *= (1 - _friction.globalRoll); + _vel.localRoll *= (1 - _friction.localRoll); } // Called if all fingers are off the screen void TouchInteraction::clear() { - _levSuccess = true; + _lmSuccess = true; + if (_directTouchMode && _selected.size() > 0) { + double fps = 0.25 / OsEng.windowWrapper().averageDeltaTime(); + if (glm::length(_lastVel.localRot) > 0.004) { // might not be desired + _vel.localRot = _lastVel.localRot * fps; + } + else if (glm::length(_lastVel.globalRot) > 0.038) { // good value to activate "spinning" + _vel.globalRot = _lastVel.globalRot * fps; + } + } if (_guiON) { bool activeLastFrame = false; if (OnScreenGUIModule::touchInput.action) { From 232ca9c26fd5533eb5c9c4f5f23860e707806f04 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 9 May 2017 13:42:35 -0600 Subject: [PATCH 085/192] cleanup in guimode --- modules/touch/include/TouchInteraction.h | 1 - modules/touch/src/TouchInteraction.cpp | 7 ------- 2 files changed, 8 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 9cfd4922b4..0aad94b868 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 30469409c6..c00784a417 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -133,13 +133,6 @@ bool TouchInteraction::gui(const std::vector& list) { } else if (_guiON) { uint32_t action = (_tap) ? 0 : 1; - - /*for (const auto& func : _moduleCallbacks.mouseButton) { - bool consumed = func(0, action); - if (consumed) { - OnScreenGUIModule::touchInput = { _guiON, pos, action }; - } - }*/ OnScreenGUIModule::touchInput = { _guiON, pos, action }; } return _guiON; // return if consumed From 08e3ac8a6b24f73d4d2a471d8332c972e658eb16 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 10 May 2017 15:09:29 -0600 Subject: [PATCH 086/192] put constants into properties instead --- ext/ghoul | 2 +- modules/touch/include/TouchInteraction.h | 38 ++++---- modules/touch/src/TouchInteraction.cpp | 117 +++++++++++++---------- modules/touch/touchmodule.cpp | 2 +- openspace.cfg | 4 +- 5 files changed, 90 insertions(+), 73 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 894358db7a..20131b6897 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 894358db7a1e15d7ae81a251aa2062ae8a48fa87 +Subproject commit 20131b68975456d4a90b5cf997dd8f10179a3a31 diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 0aad94b868..dd951e2d8a 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -56,18 +56,10 @@ namespace openspace { struct VelocityStates { + glm::dvec2 orbit; double zoom; - glm::dvec2 globalRot; - glm::dvec2 localRot; - double globalRoll; // never used - double localRoll; -}; -struct ScaleFactor { - double zoom; - double globalRot; - double localRot; // pan - double globalRoll; // never used - double localRoll; // roll + double roll; + glm::dvec2 pan; }; struct SelectedBody { int id; @@ -90,7 +82,6 @@ struct FunctionData { #define ROLL 2 #define PAN 3 #define PICK 4 -#define maxTapTime 300 using Point = std::pair; @@ -123,23 +114,34 @@ class TouchInteraction : public properties::PropertyOwner Camera* _camera; SceneGraphNode* _focusNode = nullptr; + // Property variables properties::StringProperty _origin; + properties::IntProperty _maxTapTime; properties::FloatProperty _touchScreenSize; + properties::FloatProperty _nodeRadiusThreshold; + properties::FloatProperty _orbitSpeedThreshold; + properties::FloatProperty _panSpeedThreshold; + properties::FloatProperty _spinSensitivity; + properties::FloatProperty _inputStillThreshold; + properties::FloatProperty _interpretPan; + properties::FloatProperty _slerpTime; + properties::IVec2Property _guiButton; + properties::Vec4Property _friction; + + // Class variables VelocityStates _vel; VelocityStates _lastVel; - ScaleFactor _friction; - ScaleFactor _sensitivity; + VelocityStates _sensitivity; + double _projectionScaleFactor; double _currentRadius; - double _slerpTime; + double _slerpdT; TUIO::TuioTime _time; bool _directTouchMode; bool _tap; bool _doubleTap; bool _lmSuccess; - properties::BoolProperty _guiON; - - + bool _guiON; std::vector _selected; LMstat _lmstat; glm::dquat _toSlerp; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index c00784a417..ba07b1d1d1 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -58,18 +58,36 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), - _touchScreenSize("TouchScreenSize", "Normalizes _sensitivity with screen size given in inches.", 55.0f, 5.5f, 150.0f), - _vel{ 0.0, glm::dvec2(0.0), glm::dvec2(0.0), 0.0, 0.0 }, - _friction{ 0.02, 0.01, 0.02, 1, 0.02 }, - _sensitivity{ 2.0 * 55.0, 0.1, 0.1, 1, 0.4 * 55.0 }, + _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), + _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), + _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.3f, 0.0f, 1.0f), + _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.038f, 0.0f, 0.1f), + _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.004f, 0.0, 0.01), + _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 0.25f, 0, 1), + _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0008f, 0, 0.001), + _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.01f, 0, 0.1), + _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 6, 0, 20), + _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), + _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.02, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), + + _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) }, + _sensitivity{glm::dvec2(0.1, 0.1778), 110, 22, glm::dvec2(0.1, 0.1778) }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, _slerpTime{ 1.0 }, - _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, - _guiON("Gui On", "Show GUI", false) + _currentRadius{ 1.0 }, _slerpdT{ 1000 }, + _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { + addProperty(_maxTapTime); addProperty(_touchScreenSize); - addProperty(_guiON); - levmarq_init(&_lmstat); + addProperty(_nodeRadiusThreshold); + addProperty(_orbitSpeedThreshold); + addProperty(_panSpeedThreshold); + addProperty(_spinSensitivity); + addProperty(_inputStillThreshold); + addProperty(_interpretPan); + addProperty(_slerpTime); + addProperty(_guiButton); + addProperty(_friction); + _origin.onChange([this]() { SceneGraphNode* node = sceneGraphNode(_origin.value()); if (!node) { @@ -78,6 +96,8 @@ TouchInteraction::TouchInteraction() } setFocusNode(node); }); + + levmarq_init(&_lmstat); OnScreenGUIModule::touchInput = { false, glm::vec2(0), 0 }; _time.initSession(); } @@ -87,7 +107,7 @@ TouchInteraction::~TouchInteraction() { } // Called each frame if there is any input void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { if (_tap) { // check for doubletap - if (_time.getSessionTime().getTotalMilliseconds() < maxTapTime) { + if (_time.getSessionTime().getTotalMilliseconds() < _maxTapTime) { _doubleTap = true; _tap = false; } @@ -107,7 +127,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

0.3 && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition + if (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition _directTouchMode = true; } else { @@ -120,16 +140,15 @@ bool TouchInteraction::gui(const std::vector& list) { WindowWrapper& wrapper = OsEng.windowWrapper(); glm::ivec2 res = wrapper.currentWindowSize(); glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y)); // mouse pixel position - glm::vec2 button = glm::vec2(36, 64); // pixel size _guiON = OnScreenGUIModule::gui.isEnabled(); - if (_tap && list.size() == 1 && pos.x < button.x && pos.y < button.y) { // pressed invisible button + if (_tap && list.size() == 1 && pos.x < _guiButton.value().x && pos.y < _guiButton.value().y) { // pressed invisible button _guiON = !_guiON; OnScreenGUIModule::gui.setEnabled(_guiON); std::string mode = (_guiON) ? "" : "de"; LINFO("GUI mode is " << mode << "activated. Inside box by: (" << - static_cast(100 * (pos.x / button.x)) << "%, " << static_cast(100 * (pos.y / button.y)) << "%)\n"); + static_cast(100 * (pos.x / _guiButton.value().x)) << "%, " << static_cast(100 * (pos.y / _guiButton.value().y)) << "%)\n"); } else if (_guiON) { uint32_t action = (_tap) ? 0 : 1; @@ -266,20 +285,20 @@ void TouchInteraction::manipulate(const std::vector& list) { _lmSuccess = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par if (_lmSuccess) { // if good values were found set new camera state - _vel.globalRot = glm::dvec2(par[0], par[1]); + _vel.orbit = glm::dvec2(par[0], par[1]); if (nDOF > 2) { _vel.zoom = par[2]; - _vel.localRoll = par[3]; + _vel.roll = par[3]; if (nDOF > 4) { - _vel.localRot = glm::dvec2(par[4], par[5]); + _vel.pan = glm::dvec2(par[4], par[5]); } } step(1); _lastVel = _vel; - _vel.globalRot = glm::dvec2(0.0, 0.0); + _vel.orbit = glm::dvec2(0.0, 0.0); _vel.zoom = 0.0; - _vel.localRoll = 0.0; - _vel.localRot = glm::dvec2(0.0, 0.0); + _vel.roll = 0.0; + _vel.pan = glm::dvec2(0.0, 0.0); } // debugging @@ -395,10 +414,10 @@ int TouchInteraction::interpret(const std::vector& list, const std:: return ROT; } else { - if (std::abs(dist - lastDist) / list.at(0).getMotionSpeed() < 0.01 && list.size() == 3) { // if distance between fingers is constant we have panning + if (std::abs(dist - lastDist) / list.at(0).getMotionSpeed() < _interpretPan && list.size() == 3) { // if distance between fingers is constant we have panning return PAN; } - else if (list.size() > 1 && std::abs(minDiff) < 0.0008) { // if one finger is 'still' (0.0008 works as epsilon) and another moving, we have roll + else if (list.size() > 1 && std::abs(minDiff) < _inputStillThreshold) { // if one finger is 'still' (epsilon) and another moving, we have roll return ROLL; } else { @@ -420,7 +439,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std switch (action) { case ROT: { // add rotation velocity - _vel.globalRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.globalRot; + _vel.orbit += glm::dvec2(cursor.getXSpeed() * _sensitivity.orbit.x, cursor.getYSpeed() * _sensitivity.orbit.y); break; } case PINCH: { // add zooming velocity @@ -449,26 +468,28 @@ void TouchInteraction::accelerate(const std::vector& list, const std res += currentAngle - lastAngle; return res; }); - _vel.localRoll += -rollFactor * _sensitivity.localRoll / _touchScreenSize.value(); + _vel.roll += -rollFactor * _sensitivity.roll / _touchScreenSize.value(); break; } case PAN: { // add local rotation velocity - _vel.localRot += glm::dvec2(cursor.getXSpeed(), cursor.getYSpeed()) * _sensitivity.localRot; + _vel.pan += glm::dvec2(cursor.getXSpeed() * _sensitivity.pan.x, cursor.getYSpeed() * _sensitivity.pan.y); break; } case PICK: { // pick something in the scene as focus node if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { setFocusNode(_selected.at(0).node); OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode + + // rotate camera to look at new focus glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); double angle = glm::angle(camForward, camToFocus); glm::dvec3 axis = glm::normalize(glm::cross(camForward, camToFocus)); - _toSlerp.x = axis.x * sin(angle / 2.0); // rotate camera to look at new focus + _toSlerp.x = axis.x * sin(angle / 2.0); _toSlerp.y = axis.y * sin(angle / 2.0); _toSlerp.z = axis.z * sin(angle / 2.0); _toSlerp.w = cos(angle / 2.0); - _slerpTime = 0.0; + _slerpdT = 0.0; } else { // should zoom in to current but not too much double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); @@ -478,7 +499,7 @@ void TouchInteraction::accelerate(const std::vector& list, const std factor = 1.0 + std::pow(dist / startDecline, 2); } double response = _focusNode->boundingSphere() / (factor * _currentRadius * _projectionScaleFactor); - _vel.zoom = (_sensitivity.zoom / 55) * response; + _vel.zoom = (_sensitivity.zoom / _touchScreenSize.value()) * response; } break; } @@ -514,22 +535,22 @@ void TouchInteraction::step(double dt) { _currentRadius = boundingSphere / std::max(distance * _projectionScaleFactor, 1.0); { // Roll - dquat camRollRot = angleAxis(_vel.localRoll*dt, dvec3(0.0, 0.0, 1.0)); + dquat camRollRot = angleAxis(_vel.roll*dt, dvec3(0.0, 0.0, 1.0)); localCamRot = localCamRot * camRollRot; } { // Panning (local rotation) - dvec3 eulerAngles(_vel.localRot.y*dt, _vel.localRot.x*dt, 0); + dvec3 eulerAngles(_vel.pan.y*dt, _vel.pan.x*dt, 0); dquat rotationDiff = dquat(eulerAngles); localCamRot = localCamRot * rotationDiff; // if we have chosen a new focus node - if (_slerpTime < 1) { - _slerpTime += 0.25 * dt; - localCamRot = slerp(localCamRot, _toSlerp, _slerpTime); + if (_slerpdT < _slerpTime) { + _slerpdT += dt; + localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime); } } { // Orbit (global rotation) - dvec3 eulerAngles(_vel.globalRot.y*dt, _vel.globalRot.x*dt, 0); + dvec3 eulerAngles(_vel.orbit.y*dt, _vel.orbit.x*dt, 0); dquat rotationDiffCamSpace = dquat(eulerAngles); dquat rotationDiffWorldSpace = globalCamRot * rotationDiffCamSpace * inverse(globalCamRot); @@ -557,13 +578,8 @@ void TouchInteraction::step(double dt) { _vel.zoom = 0.0; } } - { // Roll around sphere normal - is this something we ever want to do? - dquat camRollRot = angleAxis(_vel.globalRoll*dt, -directionToCenter); - globalCamRot = camRollRot * globalCamRot; - } decelerate(); - // Update the camera state _camera->setPositionVec3(camPos); _camera->setRotation(globalCamRot * localCamRot); @@ -575,26 +591,25 @@ void TouchInteraction::step(double dt) { // Decelerate velocities (set 0 for directTouch) void TouchInteraction::decelerate() { - if (!_directTouchMode && _currentRadius > 0.3 && _vel.zoom > _focusNode->boundingSphere()) { // check for velocity speed too - _vel.zoom *= (1 - 2*_friction.zoom); + if (!_directTouchMode && _currentRadius > _nodeRadiusThreshold && _vel.zoom > _focusNode->boundingSphere()) { // check for velocity speed too + _vel.zoom *= (1 - 2*_friction.value().y); } - _vel.zoom *= (1 - _friction.zoom); - _vel.globalRot *= (1 - _friction.globalRot); - _vel.localRot *= (1 - _friction.localRot); - _vel.globalRoll *= (1 - _friction.globalRoll); - _vel.localRoll *= (1 - _friction.localRoll); + _vel.orbit *= (1 - _friction.value().x); + _vel.zoom *= (1 - _friction.value().y); + _vel.roll *= (1 - _friction.value().z); + _vel.pan *= (1 - _friction.value().w); } // Called if all fingers are off the screen void TouchInteraction::clear() { _lmSuccess = true; if (_directTouchMode && _selected.size() > 0) { - double fps = 0.25 / OsEng.windowWrapper().averageDeltaTime(); - if (glm::length(_lastVel.localRot) > 0.004) { // might not be desired - _vel.localRot = _lastVel.localRot * fps; + double spinDelta = _spinSensitivity / OsEng.windowWrapper().averageDeltaTime(); + if (glm::length(_lastVel.pan) > _panSpeedThreshold) { // might not be desired + _vel.pan = _lastVel.pan * spinDelta; } - else if (glm::length(_lastVel.globalRot) > 0.038) { // good value to activate "spinning" - _vel.globalRot = _lastVel.globalRot * fps; + else if (glm::length(_lastVel.orbit) > _orbitSpeedThreshold) { // good value to activate "spinning" + _vel.orbit = _lastVel.orbit * spinDelta; } } if (_guiON) { diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 9df406b9d9..84b809b2d5 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -49,7 +49,7 @@ namespace { namespace openspace { TuioEar TouchModule::*ear; - TouchInteraction *touch; + TouchInteraction* touch; bool TouchModule::gotNewInput() { // Get new input from listener diff --git a/openspace.cfg b/openspace.cfg index 08f6ef36e1..dc126d8a42 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,13 +7,13 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - --SGCTConfig = sgct.config.single{}, + SGCTConfig = sgct.config.single{}, -- Fullscreen mode --SGCTConfig = sgct.config.single{fullScreen=true}, -- A regular 1920x1080 window - SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From 9bc653ec0170268cc61e1d9ec846e0b7ac6945c4 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 10 May 2017 17:07:54 -0600 Subject: [PATCH 087/192] save lm data for plots later --- modules/touch/ext/levmarq.cpp | 40 ++++++++++++++++++------ modules/touch/ext/levmarq.h | 5 ++- modules/touch/include/TouchInteraction.h | 1 + modules/touch/src/TouchInteraction.cpp | 15 ++++++--- modules/touch/touchmodule.cpp | 3 -- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 3b7997a29e..276ef61d39 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,7 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = 0; + lmstat->verbose = true; lmstat->max_it = 5000; lmstat->init_lambda = 1e-6; lmstat->up_factor = 10; @@ -62,7 +62,9 @@ bool levmarq(int npar, double *par, int ny, double *dysq, void (*grad)(double *, double *, int, void *), void *fdata, LMstat *lmstat) { - int x, i, j, it, nit, ill, verbose; + int x, i, j, it, nit, ill; + bool verbose; + std::string data = ""; double lambda, up, down, mult, weight, err, newerr, derr, target_derr; // allocate the arrays @@ -86,6 +88,10 @@ bool levmarq(int npar, double *par, int ny, double *dysq, weight = 1; derr = newerr = 0; // to avoid compiler warnings + if (verbose) { + data = "it,err,derr,q,g,d\n"; + } + // calculate the initial error ("chi-squared") err = error_func(par, ny, dysq, func, fdata); @@ -123,7 +129,27 @@ bool levmarq(int npar, double *par, int ny, double *dysq, ill = (derr > 0); } if (verbose) { - printf("it = %4d, lambda = %10g, err = %10g, derr = %10g (%d)\n", it, lambda, err, derr, !(newerr > err)); + /*printf("it = %4d, lambda = %10g, err = %10g, derr = %10g (%d)\n", it, lambda, err, derr, !(newerr > err)); + for (int i = 0; i < npar; ++i) { + printf("g[%d] = %g, ", i, g[i]); + } + printf("\n");*/ + + //std::ostringstream gString; + std::ostringstream gString, qString, dString, os; + for (int i = 0; i < npar; ++i) { + gString << g[i]; + qString << par[i]; + dString << d[i]; + if (i + 1 < npar) { + gString << " "; + qString << " "; + dString << " "; + } + } + os << it << "," << err << "," << derr << "," << qString.str() << "," << gString.str() << "," << dString.str() << "\n"; + data.append(os.str()); + // store iteration, error, gradient, step } if (ill) { mult = (1 + lambda * up) / (1 + lambda); @@ -143,13 +169,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq, lmstat->final_it = it; lmstat->final_err = err; lmstat->final_derr = derr; - - if (verbose) { - for (int i = 0; i < npar; ++i) { - printf("g[%d] = %g, ", i, g[i]); - } - printf("\n"); - } + lmstat->data = data; // deallocate the arrays for (int i = 0; i < npar; i++) { diff --git a/modules/touch/ext/levmarq.h b/modules/touch/ext/levmarq.h index 0009cc1324..2c8f6407f6 100644 --- a/modules/touch/ext/levmarq.h +++ b/modules/touch/ext/levmarq.h @@ -23,9 +23,12 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include typedef struct { - int verbose; + bool verbose; + std::string data; int max_it; double init_lambda; double up_factor; diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index dd951e2d8a..cdd3e19967 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -116,6 +116,7 @@ class TouchInteraction : public properties::PropertyOwner // Property variables properties::StringProperty _origin; + properties::BoolProperty _lmVerbose; properties::IntProperty _maxTapTime; properties::FloatProperty _touchScreenSize; properties::FloatProperty _nodeRadiusThreshold; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index ba07b1d1d1..e9bc5e56cc 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -58,6 +58,7 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), + _lmVerbose("LM verbose", "Save data from LM algorithm", true), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.3f, 0.0f, 1.0f), @@ -76,6 +77,7 @@ TouchInteraction::TouchInteraction() _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { + addProperty(_lmVerbose); addProperty(_maxTapTime); addProperty(_touchScreenSize); addProperty(_nodeRadiusThreshold); @@ -141,7 +143,7 @@ bool TouchInteraction::gui(const std::vector& list) { glm::ivec2 res = wrapper.currentWindowSize(); glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y)); // mouse pixel position _guiON = OnScreenGUIModule::gui.isEnabled(); - + _lmstat.verbose = _lmVerbose; if (_tap && list.size() == 1 && pos.x < _guiButton.value().x && pos.y < _guiButton.value().y) { // pressed invisible button _guiON = !_guiON; OnScreenGUIModule::gui.setEnabled(_guiON); @@ -302,11 +304,14 @@ void TouchInteraction::manipulate(const std::vector& list) { } // debugging - /*std::ostringstream os; - for (int i = 0; i < nDOF; ++i) { - os << par[i] << ", "; + if (_lmVerbose) { + /*std::ostringstream os; + for (int i = 0; i < nDOF; ++i) { + os << par[i] << ", "; + } + std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ + std::cout << _lmstat.data; } - std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ // cleanup delete[] par; diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 84b809b2d5..f84a2bae46 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -37,8 +37,6 @@ #include #include #include -#include // std::this_thread::sleep_for -#include // std::chrono::seconds using namespace TUIO; @@ -128,7 +126,6 @@ TouchModule::TouchModule() if (gotNewInput() && OsEng.windowWrapper().isMaster()) { touch->update(list, lastProcessed); - //std::this_thread::sleep_for(std::chrono::seconds(1)); // for debugging } else if (list.size() == 0) { touch->clear(); From 393e65d22b480670c7055f409e45983c25a6bb3a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 11 May 2017 13:36:53 -0600 Subject: [PATCH 088/192] set static time on unit testing --- data/scene/globebrowsing.scene | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/data/scene/globebrowsing.scene b/data/scene/globebrowsing.scene index 23506f5df1..76f358cf2d 100644 --- a/data/scene/globebrowsing.scene +++ b/data/scene/globebrowsing.scene @@ -6,11 +6,14 @@ function preInitialization() critical objects. ]]-- - --openspace.time.setTime(openspace.time.currentWallTime()) openspace.spice.loadKernel("${SPICE}/naif0012.tls") openspace.spice.loadKernel("${SPICE}/pck00010.tpc") - openspace.time.setTime(openspace.time.currentWallTime()) + -- For unit test + openspace.time.setTime("2016 SEP 8 23:00:00.500") + openspace.time.togglePause() + + --openspace.time.setTime(openspace.time.currentWallTime()) dofile(openspace.absPath('${SCRIPTS}/bind_common_keys.lua')) From cb3e31212a3fdec9e247b7c9fce2fc365cc3644d Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 11 May 2017 13:37:45 -0600 Subject: [PATCH 089/192] do a unit test on the LM algorithm and save the data to .csv --- modules/touch/ext/levmarq.cpp | 4 +- modules/touch/include/TouchInteraction.h | 3 + modules/touch/src/TouchInteraction.cpp | 70 +++++++++++++++++++++--- modules/touch/touchmodule.cpp | 1 + 4 files changed, 66 insertions(+), 12 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 276ef61d39..31729c0c23 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -128,14 +128,13 @@ bool levmarq(int npar, double *par, int ny, double *dysq, derr = newerr - err; ill = (derr > 0); } - if (verbose) { + if (verbose) { // store iteration, error, gradient, step /*printf("it = %4d, lambda = %10g, err = %10g, derr = %10g (%d)\n", it, lambda, err, derr, !(newerr > err)); for (int i = 0; i < npar; ++i) { printf("g[%d] = %g, ", i, g[i]); } printf("\n");*/ - //std::ostringstream gString; std::ostringstream gString, qString, dString, os; for (int i = 0; i < npar; ++i) { gString << g[i]; @@ -149,7 +148,6 @@ bool levmarq(int npar, double *par, int ny, double *dysq, } os << it << "," << err << "," << derr << "," << qString.str() << "," << gString.str() << "," << dString.str() << "\n"; data.append(os.str()); - // store iteration, error, gradient, step } if (ill) { mult = (1 + lambda * up) / (1 + lambda); diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index cdd3e19967..8de72fc6de 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -99,6 +99,7 @@ class TouchInteraction : public properties::PropertyOwner void accelerate(const std::vector& list, const std::vector& lastProcessed); void step(double dt); + void unitTest(); void decelerate(); void clear(); @@ -117,6 +118,7 @@ class TouchInteraction : public properties::PropertyOwner // Property variables properties::StringProperty _origin; properties::BoolProperty _lmVerbose; + properties::BoolProperty _unitTest; properties::IntProperty _maxTapTime; properties::FloatProperty _touchScreenSize; properties::FloatProperty _nodeRadiusThreshold; @@ -137,6 +139,7 @@ class TouchInteraction : public properties::PropertyOwner double _projectionScaleFactor; double _currentRadius; double _slerpdT; + int _numOfTests; TUIO::TuioTime _time; bool _directTouchMode; bool _tap; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index e9bc5e56cc..3eea25f6e1 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -46,6 +46,7 @@ #include #include +#include #include namespace { @@ -59,6 +60,7 @@ TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), _lmVerbose("LM verbose", "Save data from LM algorithm", true), + _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.3f, 0.0f, 1.0f), @@ -74,10 +76,11 @@ TouchInteraction::TouchInteraction() _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) }, _sensitivity{glm::dvec2(0.1, 0.1778), 110, 22, glm::dvec2(0.1, 0.1778) }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, _slerpdT{ 1000 }, + _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { addProperty(_lmVerbose); + addProperty(_unitTest); addProperty(_maxTapTime); addProperty(_touchScreenSize); addProperty(_nodeRadiusThreshold); @@ -116,7 +119,6 @@ void TouchInteraction::update(const std::vector& list, std::vector

0 && list.size() == _selected.size()) { manipulate(list); @@ -286,7 +288,7 @@ void TouchInteraction::manipulate(const std::vector& list) { _lmSuccess = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - if (_lmSuccess) { // if good values were found set new camera state + if (_lmSuccess && !_unitTest) { // if good values were found set new camera state _vel.orbit = glm::dvec2(par[0], par[1]); if (nDOF > 2) { _vel.zoom = par[2]; @@ -305,16 +307,14 @@ void TouchInteraction::manipulate(const std::vector& list) { // debugging if (_lmVerbose) { - /*std::ostringstream os; + /*std::cout << _lmstat.data; + std::ostringstream os; for (int i = 0; i < nDOF; ++i) { os << par[i] << ", "; } std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ - std::cout << _lmstat.data; } - - // cleanup - delete[] par; + delete[] par; // cleanup } // Traces the touch input into the scene and finds the surface coordinates of touched planets (if occuring) @@ -378,7 +378,8 @@ void TouchInteraction::trace(const std::vector& list) { //debugging for (auto it : newSelected) { - //std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; + //std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << + //", Node at:" << glm::to_string(it.node->worldPosition()) << ", Camera at: " << glm::to_string(_camera->positionVec3()) << "\n"; } } @@ -594,6 +595,57 @@ void TouchInteraction::step(double dt) { } } +void TouchInteraction::unitTest() { + if (_unitTest) { + _lmVerbose = true; + // time set and paused in .scene file + //openspace.time.setTime("2016 SEP 8 23:00:00.500") + //openspace.time.togglePause() + + using namespace glm; + // set camera pos and rot + glm::dvec3 camPos = dvec3(26974419543.178154, 76302892465.068359, -127116625827.843369); // chosen world location that fits + _camera->setPositionVec3(camPos); + + glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); + glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); + double angle = glm::angle(camForward, camToFocus); + glm::dvec3 axis = glm::normalize(glm::cross(camForward, camToFocus)); + dquat Q; + Q.x = axis.x * sin(angle / 2.0); + Q.y = axis.y * sin(angle / 2.0); + Q.z = axis.z * sin(angle / 2.0); + Q.w = cos(angle / 2.0); + dmat4 lookAtMat = lookAt( + dvec3(0, 0, 0), + normalize(camToFocus), + normalize(_camera->viewDirectionWorldSpace() + _camera->lookUpVectorWorldSpace())); // To avoid problem with lookup in up direction + dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); + _camera->setRotation(globalCamRot * Q); + + // set _selected pos and new pos (on screen) + std::vector lastFrame; + lastFrame.push_back(TuioCursor(0, 1, 0.2, 0.5)); // session id, cursor id, x, y + std::vector currFrame; + currFrame.push_back(TuioCursor(0, 1, 0.8, 0.5)); + + // call update + trace(lastFrame); + manipulate(currFrame); + + // save lmstats.data into a file and clear it + char buffer[32]; + snprintf(buffer, sizeof(char) * 32, "lmdata%i.csv", _numOfTests); + _numOfTests++; + std::ofstream file(buffer); + file << _lmstat.data; + + // clear everything + _selected.clear(); + _unitTest = false; + } +} + // Decelerate velocities (set 0 for directTouch) void TouchInteraction::decelerate() { if (!_directTouchMode && _currentRadius > _nodeRadiusThreshold && _vel.zoom > _focusNode->boundingSphere()) { // check for velocity speed too diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index f84a2bae46..12145999fa 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -136,6 +136,7 @@ TouchModule::TouchModule() for (const TuioCursor& c : list) { lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); } + touch->unitTest(); touch->step(OsEng.windowWrapper().deltaTime()); } ); From 00ce0dd56fc550043f89607695760ebb6f4dbd51 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 11 May 2017 16:45:36 -0600 Subject: [PATCH 090/192] improvement on unit test --- modules/touch/ext/levmarq.cpp | 60 ++++++++++++++++++------ modules/touch/ext/levmarq.h | 9 ++-- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 18 +++---- 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 31729c0c23..8255246e0a 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -58,8 +58,8 @@ Before calling levmarq, several of the parameters in lmstat must be set. For default values, call levmarq_init(lmstat). */ bool levmarq(int npar, double *par, int ny, double *dysq, - double (*func)(double *, int, void *), - void (*grad)(double *, double *, int, void *), + double (*func)(double *, int, void *, LMstat*), + void (*grad)(double *, double *, int, void *, LMstat*), void *fdata, LMstat *lmstat) { int x, i, j, it, nit, ill; @@ -89,11 +89,36 @@ bool levmarq(int npar, double *par, int ny, double *dysq, derr = newerr = 0; // to avoid compiler warnings if (verbose) { - data = "it,err,derr,q,g,d\n"; + std::ostringstream qs, gs, ds, ps, oss; + for (int i = 0; i < npar; ++i) { + qs << "q" << i; + gs << "g" << i; + ds << "q" << i; + if (i + 1 < npar) { + qs << ","; + gs << ","; + ds << ","; + } + } + int k = 1; + for (int i = 0; i < ny; ++i) { + for (int j = 0; j < ny; ++j) { + ps << "pos" << i << j; + if (j + 1 < ny) { + ps << ","; + } + } + if (i + 1 < ny) { + ps << ","; + } + } + oss << "it,err,derr," << qs.str() << "," << gs.str() << "," << ds.str() << "," << ps.str() << "\n"; + data = oss.str(); } // calculate the initial error ("chi-squared") - err = error_func(par, ny, dysq, func, fdata); + lmstat->pos.clear(); + err = error_func(par, ny, dysq, func, fdata, lmstat); // main iteration for (it = 0; it < nit; it++) { @@ -106,9 +131,9 @@ bool levmarq(int npar, double *par, int ny, double *dysq, for (x = 0; x < ny; x++) { if (dysq) weight = 1/dysq[x]; // for weighted least-squares - grad(g, par, x, fdata); + grad(g, par, x, fdata, lmstat); for (i = 0; i < npar; i++) { - d[i] += (0.0 - func(par, x, fdata)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight; + d[i] += (0.0 - func(par, x, fdata, lmstat)) * g[i] * weight; //(y[x] - func(par, x, fdata)) * g[i] * weight; for (j = 0; j <= i; j++) h[i][j] += g[i] * g[j] * weight; } @@ -124,7 +149,8 @@ bool levmarq(int npar, double *par, int ny, double *dysq, solve_axb_cholesky(npar, ch, delta, d); for (i = 0; i < npar; i++) newpar[i] = par[i] + delta[i]; - newerr = error_func(newpar, ny, dysq, func, fdata); + lmstat->pos.clear(); + newerr = error_func(newpar, ny, dysq, func, fdata, lmstat); derr = newerr - err; ill = (derr > 0); } @@ -135,18 +161,24 @@ bool levmarq(int npar, double *par, int ny, double *dysq, } printf("\n");*/ - std::ostringstream gString, qString, dString, os; + std::ostringstream gString, qString, dString, pString, os; for (int i = 0; i < npar; ++i) { gString << g[i]; qString << par[i]; dString << d[i]; if (i + 1 < npar) { - gString << " "; - qString << " "; - dString << " "; + gString << ","; + qString << ","; + dString << ","; } } - os << it << "," << err << "," << derr << "," << qString.str() << "," << gString.str() << "," << dString.str() << "\n"; + for (int i = 0; i < ny; ++i) { + pString << lmstat->pos.at(i).x << "," << lmstat->pos.at(i).y; + if (i + 1 < ny) { + pString << ","; + } + } + os << it << "," << err << "," << derr << "," << qString.str() << "," << gString.str() << "," << dString.str() << "," << pString.str() << "\n"; data.append(os.str()); } if (ill) { @@ -187,12 +219,12 @@ bool levmarq(int npar, double *par, int ny, double *dysq, // calculate the error function (chi-squared) double error_func(double *par, int ny, double *dysq, - double (*func)(double *, int, void *), void *fdata) { + double (*func)(double *, int, void *, LMstat*), void *fdata, LMstat *lmstat) { int x; double res, e = 0; for (x = 0; x < ny; x++) { - res = func(par, x, fdata); + res = func(par, x, fdata, lmstat); if (dysq) // weighted least-squares e += res*res/dysq[x]; else diff --git a/modules/touch/ext/levmarq.h b/modules/touch/ext/levmarq.h index 2c8f6407f6..d3c7d77892 100644 --- a/modules/touch/ext/levmarq.h +++ b/modules/touch/ext/levmarq.h @@ -25,10 +25,13 @@ OTHER DEALINGS IN THE SOFTWARE. */ #include #include +#include +#include typedef struct { bool verbose; std::string data; + std::vector pos; int max_it; double init_lambda; double up_factor; @@ -42,12 +45,12 @@ typedef struct { void levmarq_init(LMstat *lmstat); bool levmarq(int npar, double *par, int ny, double *dysq, - double (*func)(double *, int, void *), - void (*grad)(double *, double *, int, void *), + double (*func)(double *, int, void *, LMstat*), + void (*grad)(double *, double *, int, void *, LMstat*), void *fdata, LMstat *lmstat); double error_func(double *par, int ny, double *dysq, - double (*func)(double *, int, void *), void *fdata); + double (*func)(double *, int, void *, LMstat*), void *fdata, LMstat* lmstat); void solve_axb_cholesky(int n, double** l, double* x, double* b); diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 8de72fc6de..0de5509b98 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -71,10 +71,11 @@ struct FunctionData { std::vector screenPoints; int nDOF; glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*, double); - double(*distToMinimize)(double* par, int x, void* fdata); + double(*distToMinimize)(double* par, int x, void* fdata, LMstat* lmstat); Camera* camera; SceneGraphNode* node; double aspectRatio; + LMstat stats; }; #define ROT 0 diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 3eea25f6e1..8039e4984f 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -164,7 +164,7 @@ bool TouchInteraction::gui(const std::vector& list) { // Sets _vel to update _camera according to direct-manipulation (L2 error) void TouchInteraction::manipulate(const std::vector& list) { // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi - auto distToMinimize = [](double* par, int x, void* fdata) { + auto distToMinimize = [](double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); // Apply transform to camera and find the new screen point of the updated camera state @@ -228,13 +228,13 @@ void TouchInteraction::manipulate(const std::vector& list) { // we now have a new position and orientation of camera, project surfacePoint to the new screen to get distance to minimize glm::dvec2 newScreenPoint = ptr->castToNDC(ptr->selectedPoints.at(x), cam, ptr->node, ptr->aspectRatio); - + lmstat->pos.push_back(newScreenPoint); return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; // Gradient of distToMinimize w.r.t par (using forward difference) - auto gradient = [](double* g, double* par, int x, void* fdata) { + auto gradient = [](double* g, double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); - double f0 = ptr->distToMinimize(par, x, fdata); + double f0 = ptr->distToMinimize(par, x, fdata, lmstat); double f1, der, minStep = 1e-11; glm::dvec3 camPos = ptr->camera->positionVec3(); glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); @@ -247,7 +247,7 @@ void TouchInteraction::manipulate(const std::vector& list) { for (int i = 0; i < ptr->nDOF; ++i) { h = (i == 2) ? 1e-4 : h; // the 'zoom'-DOF is so big a smaller step creates NAN dPar[i] += h; - f1 = ptr->distToMinimize(dPar, x, fdata); + f1 = ptr->distToMinimize(dPar, x, fdata, lmstat); dPar[i] -= h; der = (f1 - f0) / h; @@ -283,7 +283,7 @@ void TouchInteraction::manipulate(const std::vector& list) { screenPoints.push_back(glm::dvec2(xCo, yCo)); } //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88 }; + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88, _lmstat }; void* dataPtr = reinterpret_cast(&fData); _lmSuccess = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par @@ -625,9 +625,11 @@ void TouchInteraction::unitTest() { // set _selected pos and new pos (on screen) std::vector lastFrame; - lastFrame.push_back(TuioCursor(0, 1, 0.2, 0.5)); // session id, cursor id, x, y + lastFrame.push_back(TuioCursor(0, 10, 0.45, 0.4)); // session id, cursor id, x, y + lastFrame.push_back(TuioCursor(1, 11, 0.55, 0.6)); std::vector currFrame; - currFrame.push_back(TuioCursor(0, 1, 0.8, 0.5)); + currFrame.push_back(TuioCursor(0, 10, 0.2, 0.6)); // (-0.6,0) + currFrame.push_back(TuioCursor(1, 11, 0.8, 0.4)); // (0.6, 0) // call update trace(lastFrame); From 3a6f2a54e51e940e0f84e4d3eeb2c917c9646f19 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 11 May 2017 23:25:13 -0400 Subject: [PATCH 091/192] Add some comments --- modules/touch/include/TouchInteraction.h | 16 ++++++++++++++-- modules/touch/src/TouchInteraction.cpp | 11 +++++++++++ modules/touch/touchmodule.cpp | 13 ++++++++++++- modules/touch/touchmodule.h | 4 ++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 0de5509b98..e7fd5ce07a 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -47,6 +47,9 @@ #include +// @COMMENT It's better to use strongly-typed enums here: +// enum class Type { Rot = 0, Pinch, Pan, Roll, Pick }; +// #define's leak into other parts of the program, especially if they are defined in header files #define ROT 0 #define PINCH 1 #define PAN 2 @@ -55,6 +58,8 @@ namespace openspace { +// @COMMENT These structs are defined in the openspace namespace; it would be better to place that in either +// a subnamespace or in the Touchinteraction class struct VelocityStates { glm::dvec2 orbit; double zoom; @@ -78,22 +83,29 @@ struct FunctionData { LMstat stats; }; +// @COMMENT Double definition #define ROT 0 #define PINCH 1 #define ROLL 2 #define PAN 3 #define PICK 4 +// @COMMENT This is also polluting the openspace namespace using Point = std::pair; class TouchInteraction : public properties::PropertyOwner { public: TouchInteraction(); + // @COMMENT The destructor doesn't do anything, so it could be deleted ~TouchInteraction(); - void update(const std::vector& list, std::vector& lastProcessed); - bool gui(const std::vector& list); + // @COMMENT How many of these functions have to be public, and could be made private instead? + + void update(const std::vector& list, std::vector& lastProcessed); + // @COMMENT all of the function names here are not very descriptive. Especially + // when it comes to the return values + bool gui(const std::vector& list); void manipulate(const std::vector& list); void trace(const std::vector& list); int interpret(const std::vector& list, const std::vector& lastProcessed); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 8039e4984f..c0647bdb89 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -54,6 +54,7 @@ namespace { } using namespace TUIO; +// @COMMENT Instead of using namespace openspace, it's better to just open the namespace instead using namespace openspace; TouchInteraction::TouchInteraction() @@ -222,6 +223,7 @@ void TouchInteraction::manipulate(const std::vector& list) { } // Update the camera state + // @COMMENT Do you have to make a copy of the camera object here? You are not using it afterwards Camera cam = *(ptr->camera); cam.setPositionVec3(camPos); cam.setRotation(globalCamRot * localCamRot); @@ -239,6 +241,7 @@ void TouchInteraction::manipulate(const std::vector& list) { glm::dvec3 camPos = ptr->camera->positionVec3(); glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); double h = minStep * glm::distance(camPos, selectedPoint); + // @COMMENT Is it necessary to make the allication every time? It might better to only allocate the memory once (preferrably on the heap) double* dPar = new double[ptr->nDOF]; for (int i = 0; i < ptr->nDOF; ++i) { dPar[i] = par[i]; @@ -268,6 +271,7 @@ void TouchInteraction::manipulate(const std::vector& list) { const int nFingers = list.size(); int nDOF = std::min(nFingers * 2, 6); + // @COMMENT Better to use a std::vector(nDOF, 0.0) here and use par.data() where you need to pass the * to other functions. Then you can remove the next for loop, too double* par = new double[nDOF]; for (int i = 0; i < nDOF; ++i) { // initial values of q or 0.0? (ie current model or no rotation/translation) par[i] = 0.0; @@ -331,6 +335,7 @@ void TouchInteraction::trace(const std::vector& list) { selectableNodes.push_back(node); //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); + // @COMMENT ^_^ double aspectRatio = 1.88; //res.x/res.y; glm::dquat camToWorldSpace = _camera->rotationQuaternion(); glm::dvec3 camPos = _camera->positionVec3(); @@ -385,6 +390,7 @@ void TouchInteraction::trace(const std::vector& list) { // Interprets the input gesture to a specific interaction int TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { + // @COMMENT #include Then you can use ghoul_precondition as an assertion to check if, for example, list is not empty double dist = 0; double lastDist = 0; TuioCursor cursor = list.at(0); @@ -627,6 +633,11 @@ void TouchInteraction::unitTest() { std::vector lastFrame; lastFrame.push_back(TuioCursor(0, 10, 0.45, 0.4)); // session id, cursor id, x, y lastFrame.push_back(TuioCursor(1, 11, 0.55, 0.6)); + // @COMMENT Alternative way of specifying: + // std::vector lastFrame = { + // { (0, 10, 0.45, 0.4 }, + // { (1, 11, 0.55, 0.6 } + // }; std::vector currFrame; currFrame.push_back(TuioCursor(0, 10, 0.2, 0.6)); // (-0.6,0) currFrame.push_back(TuioCursor(1, 11, 0.8, 0.4)); // (0.6, 0) diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 12145999fa..e48b8fc3d0 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -46,7 +46,10 @@ namespace { namespace openspace { + // @COMMENT What does this do? TuioEar TouchModule::*ear; + + // @COMMENT Definining this globally makes it potentially dangerous. Is it necessary or better to put into the class? TouchInteraction* touch; bool TouchModule::gotNewInput() { @@ -73,14 +76,18 @@ bool TouchModule::gotNewInput() { if (list.size() == 0 && lastProcessed.size() == 0 && ear->tap()) { TuioCursor c = ear->getTap(); list.push_back(c); + // @COMMENT You can use: + // lastProcessed.emplace_back(c.getSessionID(), c.getPath().back()); lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); touch->tap(); return true; } // Return true if we got new input + // @COMMENT You can use !list.empty() if (list.size() == lastProcessed.size() && list.size() > 0) { bool newInput = true; + // @COMMENT Why can you use for_each without std:: ? It seems like there is a using namespace std somewhere for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { std::vector::iterator cursor = find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); double now = cursor->getPath().back().getTuioTime().getTotalMilliseconds(); @@ -98,7 +105,9 @@ bool TouchModule::gotNewInput() { TouchModule::TouchModule() : OpenSpaceModule("Touch") { - + // @COMMENT If TuioEar and TouchInteraction don't have any dependencies and if they + // can be initialized immediately and you don't need to register a callback + // Even better would be to not even use pointers but direct member instances instead OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::Initialize, [&]() { @@ -134,6 +143,8 @@ TouchModule::TouchModule() // update lastProcessed lastProcessed.clear(); for (const TuioCursor& c : list) { + // @COMMENT You can use: + // lastProcessed.emplace_back(c.getSessionID(), c.getPath().back()); lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); } touch->unitTest(); diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 6fbf907b26..8af4aa15d9 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -33,18 +33,22 @@ namespace openspace { +// @COMMENT This is defined in global namespace, maybe place in separate namespace or inside the TouchModule? using Point = std::pair; class TouchModule : public OpenSpaceModule { public: TouchModule(); + // @COMMENT better name: hasNewInput bool gotNewInput(); + // @COMMENT Does it makes sense to make this available as a public variable? TuioEar* ear; private: + // @COMMENT list is a very undescriptive name std::vector list; std::vector lastProcessed; // contains an id and the TuioPoint that was processed last frame From f10c3783fa26b0d520954b5ec493684446c7836a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 12 May 2017 09:42:46 -0600 Subject: [PATCH 092/192] set lmverbose to false as default --- ext/ghoul | 2 +- modules/touch/ext/levmarq.cpp | 2 +- modules/touch/src/TouchInteraction.cpp | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 20131b6897..894358db7a 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 20131b68975456d4a90b5cf997dd8f10179a3a31 +Subproject commit 894358db7a1e15d7ae81a251aa2062ae8a48fa87 diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 8255246e0a..75be500d68 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -30,7 +30,7 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { - lmstat->verbose = true; + lmstat->verbose = false; lmstat->max_it = 5000; lmstat->init_lambda = 1e-6; lmstat->up_factor = 10; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index c0647bdb89..5a8a378fb3 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -60,7 +60,7 @@ using namespace openspace; TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), - _lmVerbose("LM verbose", "Save data from LM algorithm", true), + _lmVerbose("LM verbose", "Save data from LM algorithm", false), _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), @@ -603,7 +603,7 @@ void TouchInteraction::step(double dt) { void TouchInteraction::unitTest() { if (_unitTest) { - _lmVerbose = true; + _lmVerbose = _lmstat.verbose = true; // time set and paused in .scene file //openspace.time.setTime("2016 SEP 8 23:00:00.500") //openspace.time.togglePause() @@ -656,6 +656,7 @@ void TouchInteraction::unitTest() { // clear everything _selected.clear(); _unitTest = false; + _lmVerbose = false; } } From fb79cfe5f3483120dff8a62484022c638a2c6f85 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 12 May 2017 11:18:17 -0600 Subject: [PATCH 093/192] classes defined in module class and cleanup --- modules/touch/touchmodule.cpp | 91 ++++++++++++----------------------- modules/touch/touchmodule.h | 31 +++++------- 2 files changed, 43 insertions(+), 79 deletions(-) diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index e48b8fc3d0..d580835890 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -46,16 +46,10 @@ namespace { namespace openspace { - // @COMMENT What does this do? - TuioEar TouchModule::*ear; - - // @COMMENT Definining this globally makes it potentially dangerous. Is it necessary or better to put into the class? - TouchInteraction* touch; - -bool TouchModule::gotNewInput() { +bool TouchModule::hasNewInput() { // Get new input from listener - list = ear->getInput(); - ear->clearInput(); + listOfContactPoints = ear.getInput(); + ear.clearInput(); // Erase old input id's that no longer exists lastProcessed.erase( @@ -64,91 +58,70 @@ bool TouchModule::gotNewInput() { lastProcessed.end(), [this](const Point& point) { return std::find_if( - list.begin(), - list.end(), + listOfContactPoints.begin(), + listOfContactPoints.end(), [&point](const TuioCursor& c) { return point.first == c.getSessionID(); } - ) == list.end(); }), + ) == listOfContactPoints.end(); }), lastProcessed.end()); // Tap - if (list.size() == 0 && lastProcessed.size() == 0 && ear->tap()) { - TuioCursor c = ear->getTap(); - list.push_back(c); - // @COMMENT You can use: - // lastProcessed.emplace_back(c.getSessionID(), c.getPath().back()); - lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); - touch->tap(); + if (listOfContactPoints.empty() && lastProcessed.empty() && ear.tap()) { + TuioCursor c = ear.getTap(); + listOfContactPoints.push_back(c); + lastProcessed.emplace_back(c.getSessionID(), c.getPath().back()); + touch.tap(); return true; } // Return true if we got new input - // @COMMENT You can use !list.empty() - if (list.size() == lastProcessed.size() && list.size() > 0) { + if (listOfContactPoints.size() == lastProcessed.size() && !listOfContactPoints.empty()) { bool newInput = true; // @COMMENT Why can you use for_each without std:: ? It seems like there is a using namespace std somewhere - for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { - std::vector::iterator cursor = find_if(list.begin(), list.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); + std::for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { + std::vector::iterator cursor = find_if(listOfContactPoints.begin(), listOfContactPoints.end(), + [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); double now = cursor->getPath().back().getTuioTime().getTotalMilliseconds(); - if (!cursor->isMoving()) + if (!cursor->isMoving()) { newInput = true; - else if (p.second.getTuioTime().getTotalMilliseconds() == now) + } + else if (p.second.getTuioTime().getTotalMilliseconds() == now) { newInput = false; + } }); return newInput; } - else + else { return false; + } } TouchModule::TouchModule() : OpenSpaceModule("Touch") { - // @COMMENT If TuioEar and TouchInteraction don't have any dependencies and if they - // can be initialized immediately and you don't need to register a callback - // Even better would be to not even use pointers but direct member instances instead - OsEng.registerModuleCallback( - OpenSpaceEngine::CallbackOption::Initialize, - [&]() { - LDEBUGC("TouchModule", "Initializing TuioEar"); - ear = new TuioEar(); - touch = new TouchInteraction(); - addPropertySubOwner(touch); - } - ); - - OsEng.registerModuleCallback( - OpenSpaceEngine::CallbackOption::Deinitialize, - [&]() { - LDEBUGC("TouchModule", "Deinitialize TuioEar"); - delete ear; - delete touch; - } - ); + addPropertySubOwner(touch); OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::PreSync, [&]() { - touch->setCamera(OsEng.interactionHandler().camera()); - touch->setFocusNode(OsEng.interactionHandler().focusNode()); + touch.setCamera(OsEng.interactionHandler().camera()); + touch.setFocusNode(OsEng.interactionHandler().focusNode()); - if (gotNewInput() && OsEng.windowWrapper().isMaster()) { - touch->update(list, lastProcessed); + if (hasNewInput() && OsEng.windowWrapper().isMaster()) { + touch.updateStateFromInput(listOfContactPoints, lastProcessed); } - else if (list.size() == 0) { - touch->clear(); + else if (listOfContactPoints.empty()) { + touch.resetAfterInput(); } // update lastProcessed lastProcessed.clear(); - for (const TuioCursor& c : list) { - // @COMMENT You can use: - // lastProcessed.emplace_back(c.getSessionID(), c.getPath().back()); - lastProcessed.push_back(std::make_pair(c.getSessionID(), c.getPath().back())); + for (const TuioCursor& c : listOfContactPoints) { + lastProcessed.emplace_back(c.getSessionID(), c.getPath().back()); } - touch->unitTest(); - touch->step(OsEng.windowWrapper().deltaTime()); + touch.unitTest(); + touch.step(OsEng.windowWrapper().deltaTime()); } ); diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 8af4aa15d9..763063e88c 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -29,30 +29,21 @@ #include #include - - namespace openspace { -// @COMMENT This is defined in global namespace, maybe place in separate namespace or inside the TouchModule? -using Point = std::pair; + class TouchModule : public OpenSpaceModule { + public: + using Point = std::pair; + TouchModule(); -class TouchModule : public OpenSpaceModule { -public: - TouchModule(); + private: + bool hasNewInput(); - // @COMMENT better name: hasNewInput - bool gotNewInput(); - - // @COMMENT Does it makes sense to make this available as a public variable? - TuioEar* ear; - - -private: - // @COMMENT list is a very undescriptive name - std::vector list; - std::vector lastProcessed; // contains an id and the TuioPoint that was processed last frame - -}; + TuioEar ear; + TouchInteraction touch; + std::vector listOfContactPoints; + std::vector lastProcessed; // contains an id and the TuioPoint that was processed last frame + }; } // namespace openspace From e854b1de3fb39454287a84f4a265d534e710d6b6 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 12 May 2017 11:18:48 -0600 Subject: [PATCH 094/192] cleanup and fixes from code review --- modules/touch/include/TouchInteraction.h | 97 +++++++++--------------- modules/touch/src/TouchInteraction.cpp | 94 +++++++++-------------- modules/touch/src/TuioEar.cpp | 10 +-- 3 files changed, 78 insertions(+), 123 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index e7fd5ce07a..e75a6c3c7b 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -25,9 +25,8 @@ #ifndef __OPENSPACE_TOUCH___INTERACTION___H__ #define __OPENSPACE_TOUCH___INTERACTION___H__ -#include -#include #include +#include #include #include @@ -47,75 +46,44 @@ #include -// @COMMENT It's better to use strongly-typed enums here: -// enum class Type { Rot = 0, Pinch, Pan, Roll, Pick }; -// #define's leak into other parts of the program, especially if they are defined in header files -#define ROT 0 -#define PINCH 1 -#define PAN 2 -#define ROLL 3 -#define PICK 4 - namespace openspace { -// @COMMENT These structs are defined in the openspace namespace; it would be better to place that in either -// a subnamespace or in the Touchinteraction class -struct VelocityStates { - glm::dvec2 orbit; - double zoom; - double roll; - glm::dvec2 pan; -}; -struct SelectedBody { - int id; - SceneGraphNode* node; - glm::dvec3 coordinates; -}; -struct FunctionData { - std::vector selectedPoints; - std::vector screenPoints; - int nDOF; - glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*, double); - double(*distToMinimize)(double* par, int x, void* fdata, LMstat* lmstat); - Camera* camera; - SceneGraphNode* node; - double aspectRatio; - LMstat stats; -}; - -// @COMMENT Double definition -#define ROT 0 -#define PINCH 1 -#define ROLL 2 -#define PAN 3 -#define PICK 4 - -// @COMMENT This is also polluting the openspace namespace -using Point = std::pair; - class TouchInteraction : public properties::PropertyOwner { + using Point = std::pair; + public: TouchInteraction(); - // @COMMENT The destructor doesn't do anything, so it could be deleted - ~TouchInteraction(); - - // @COMMENT How many of these functions have to be public, and could be made private instead? - void update(const std::vector& list, std::vector& lastProcessed); - // @COMMENT all of the function names here are not very descriptive. Especially - // when it comes to the return values - bool gui(const std::vector& list); - void manipulate(const std::vector& list); - void trace(const std::vector& list); - int interpret(const std::vector& list, const std::vector& lastProcessed); - void accelerate(const std::vector& list, const std::vector& lastProcessed); + enum Type { ROT = 0, PINCH, PAN, ROLL, PICK }; + struct VelocityStates { + glm::dvec2 orbit; + double zoom; + double roll; + glm::dvec2 pan; + }; + struct SelectedBody { + int id; + SceneGraphNode* node; + glm::dvec3 coordinates; + }; + struct FunctionData { + std::vector selectedPoints; + std::vector screenPoints; + int nDOF; + glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*, double); + double(*distToMinimize)(double* par, int x, void* fdata, LMstat* lmstat); + Camera* camera; + SceneGraphNode* node; + double aspectRatio; + LMstat stats; + }; + + void updateStateFromInput(const std::vector& list, std::vector& lastProcessed); void step(double dt); void unitTest(); - - void decelerate(); - void clear(); + void resetAfterInput(); void tap(); // Get & Setters @@ -125,6 +93,13 @@ class TouchInteraction : public properties::PropertyOwner void setCamera(Camera* cam); private: + bool guiMode(const std::vector& list); + void directControl(const std::vector& list); + void findSelectedNode(const std::vector& list); + int interpretInteraction(const std::vector& list, const std::vector& lastProcessed); + void computeVelocities(const std::vector& list, const std::vector& lastProcessed); + void decelerate(); + Camera* _camera; SceneGraphNode* _focusNode = nullptr; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 5a8a378fb3..9af6f1af03 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -22,7 +22,6 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ - #include #include @@ -54,8 +53,7 @@ namespace { } using namespace TUIO; -// @COMMENT Instead of using namespace openspace, it's better to just open the namespace instead -using namespace openspace; +namespace openspace { TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), @@ -108,10 +106,8 @@ TouchInteraction::TouchInteraction() _time.initSession(); } -TouchInteraction::~TouchInteraction() { } - // Called each frame if there is any input -void TouchInteraction::update(const std::vector& list, std::vector& lastProcessed) { +void TouchInteraction::updateStateFromInput(const std::vector& list, std::vector& lastProcessed) { if (_tap) { // check for doubletap if (_time.getSessionTime().getTotalMilliseconds() < _maxTapTime) { _doubleTap = true; @@ -120,19 +116,19 @@ void TouchInteraction::update(const std::vector& list, std::vector

0 && list.size() == _selected.size()) { - manipulate(list); + directControl(list); } if (_lmSuccess) { - trace(list); + findSelectedNode(list); } if (!_directTouchMode) { - accelerate(list, lastProcessed); + computeVelocities(list, lastProcessed); } // evaluates if current frame is in directTouchMode (will if so be used next frame) - if (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()) { // good value to make any planet sufficiently large for direct-touch, needs better definition + if (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()) { // needs better definition? _directTouchMode = true; } else { @@ -141,7 +137,7 @@ void TouchInteraction::update(const std::vector& list, std::vector

& list) { +bool TouchInteraction::guiMode(const std::vector& list) { WindowWrapper& wrapper = OsEng.windowWrapper(); glm::ivec2 res = wrapper.currentWindowSize(); glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y)); // mouse pixel position @@ -163,7 +159,7 @@ bool TouchInteraction::gui(const std::vector& list) { } // Sets _vel to update _camera according to direct-manipulation (L2 error) -void TouchInteraction::manipulate(const std::vector& list) { +void TouchInteraction::directControl(const std::vector& list) { // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi auto distToMinimize = [](double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); @@ -236,27 +232,20 @@ void TouchInteraction::manipulate(const std::vector& list) { // Gradient of distToMinimize w.r.t par (using forward difference) auto gradient = [](double* g, double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); - double f0 = ptr->distToMinimize(par, x, fdata, lmstat); - double f1, der, minStep = 1e-11; glm::dvec3 camPos = ptr->camera->positionVec3(); glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); - double h = minStep * glm::distance(camPos, selectedPoint); - // @COMMENT Is it necessary to make the allication every time? It might better to only allocate the memory once (preferrably on the heap) - double* dPar = new double[ptr->nDOF]; - for (int i = 0; i < ptr->nDOF; ++i) { - dPar[i] = par[i]; - } + double h = 1e-11 * glm::distance(camPos, selectedPoint); + double der, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); for (int i = 0; i < ptr->nDOF; ++i) { h = (i == 2) ? 1e-4 : h; // the 'zoom'-DOF is so big a smaller step creates NAN - dPar[i] += h; - f1 = ptr->distToMinimize(dPar, x, fdata, lmstat); - dPar[i] -= h; + par[i] += h; + f1 = ptr->distToMinimize(par, x, fdata, lmstat); + par[i] -= h; der = (f1 - f0) / h; g[i] = (i > 1 && i < 4) ? der : der / abs(der); } - delete[] dPar; }; SceneGraphNode* node = _selected.at(0).node; @@ -271,34 +260,28 @@ void TouchInteraction::manipulate(const std::vector& list) { const int nFingers = list.size(); int nDOF = std::min(nFingers * 2, 6); - // @COMMENT Better to use a std::vector(nDOF, 0.0) here and use par.data() where you need to pass the * to other functions. Then you can remove the next for loop, too - double* par = new double[nDOF]; - for (int i = 0; i < nDOF; ++i) { // initial values of q or 0.0? (ie current model or no rotation/translation) - par[i] = 0.0; - } + std::vector par(nDOF, 0.0); std::vector selectedPoints; std::vector screenPoints; for (const SelectedBody& sb : _selected) { selectedPoints.push_back(sb.coordinates); std::vector::const_iterator c = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return c.getSessionID() == sb.id; }); - double xCo = 2 * (c->getX() - 0.5); - double yCo = -2 * (c->getY() - 0.5); // normalized -1 to 1 coordinates on screen - screenPoints.push_back(glm::dvec2(xCo, yCo)); + screenPoints.push_back(glm::dvec2(2 * (c->getX() - 0.5), -2 * (c->getY() - 0.5))); // normalized -1 to 1 coordinates on screen } //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88, _lmstat }; void* dataPtr = reinterpret_cast(&fData); - _lmSuccess = levmarq(nDOF, par, nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par + _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par if (_lmSuccess && !_unitTest) { // if good values were found set new camera state - _vel.orbit = glm::dvec2(par[0], par[1]); + _vel.orbit = glm::dvec2(par.at(0), par.at(1)); if (nDOF > 2) { - _vel.zoom = par[2]; - _vel.roll = par[3]; + _vel.zoom = par.at(2); + _vel.roll = par.at(3); if (nDOF > 4) { - _vel.pan = glm::dvec2(par[4], par[5]); + _vel.pan = glm::dvec2(par.at(4), par.at(5)); } } step(1); @@ -318,11 +301,10 @@ void TouchInteraction::manipulate(const std::vector& list) { } std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ } - delete[] par; // cleanup } // Traces the touch input into the scene and finds the surface coordinates of touched planets (if occuring) -void TouchInteraction::trace(const std::vector& list) { +void TouchInteraction::findSelectedNode(const std::vector& list) { //trim list to only contain visible nodes that make sense std::string selectables[30] = { "Sun", "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", @@ -389,7 +371,7 @@ void TouchInteraction::trace(const std::vector& list) { } // Interprets the input gesture to a specific interaction -int TouchInteraction::interpret(const std::vector& list, const std::vector& lastProcessed) { +int TouchInteraction::interpretInteraction(const std::vector& list, const std::vector& lastProcessed) { // @COMMENT #include Then you can use ghoul_precondition as an assertion to check if, for example, list is not empty double dist = 0; double lastDist = 0; @@ -439,10 +421,10 @@ int TouchInteraction::interpret(const std::vector& list, const std:: } // Calculate how much interpreted interaction should change the camera state (based on _vel) -void TouchInteraction::accelerate(const std::vector& list, const std::vector& lastProcessed) { +void TouchInteraction::computeVelocities(const std::vector& list, const std::vector& lastProcessed) { TuioCursor cursor = list.at(0); glm::dvec3 centroid; - int action = interpret(list, lastProcessed); + int action = interpretInteraction(list, lastProcessed); if (action != ROT || action != PICK) { centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); @@ -630,21 +612,18 @@ void TouchInteraction::unitTest() { _camera->setRotation(globalCamRot * Q); // set _selected pos and new pos (on screen) - std::vector lastFrame; - lastFrame.push_back(TuioCursor(0, 10, 0.45, 0.4)); // session id, cursor id, x, y - lastFrame.push_back(TuioCursor(1, 11, 0.55, 0.6)); - // @COMMENT Alternative way of specifying: - // std::vector lastFrame = { - // { (0, 10, 0.45, 0.4 }, - // { (1, 11, 0.55, 0.6 } - // }; - std::vector currFrame; - currFrame.push_back(TuioCursor(0, 10, 0.2, 0.6)); // (-0.6,0) - currFrame.push_back(TuioCursor(1, 11, 0.8, 0.4)); // (0.6, 0) + std::vector lastFrame = { + { TuioCursor(0, 10, 0.45, 0.4) }, // session id, cursor id, x, y + { TuioCursor(1, 11, 0.55, 0.6) } + }; + std::vector currFrame = { + { TuioCursor(0, 10, 0.2, 0.6) }, // (-0.6,-0.2) + { TuioCursor(1, 11, 0.8, 0.4) } // (0.6, 0.2) + }; // call update - trace(lastFrame); - manipulate(currFrame); + findSelectedNode(lastFrame); + directControl(currFrame); // save lmstats.data into a file and clear it char buffer[32]; @@ -672,7 +651,7 @@ void TouchInteraction::decelerate() { } // Called if all fingers are off the screen -void TouchInteraction::clear() { +void TouchInteraction::resetAfterInput() { _lmSuccess = true; if (_directTouchMode && _selected.size() > 0) { double spinDelta = _spinSensitivity / OsEng.windowWrapper().averageDeltaTime(); @@ -715,3 +694,4 @@ void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { _focusNode = focusNode; } +} // openspace namespace \ No newline at end of file diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index abc6f93748..b5b4c0e086 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -35,7 +35,6 @@ #include using namespace TUIO; - namespace { const std::string _loggerCat = "TuioEar"; } @@ -66,9 +65,9 @@ void TuioEar::addTuioCursor(TuioCursor *tcur) { })->update(tcur); _removeList.erase(foundID); } - else + else { _list.push_back(TuioCursor(*tcur)); - + } _mx.unlock(); } @@ -115,8 +114,9 @@ bool TuioEar::tap() { _tap = false; return !_tap; } - else + else { return _tap; + } } TuioCursor TuioEar::getTap() { @@ -150,4 +150,4 @@ TuioEar::TuioEar() { _tuioClient = new TuioClient(_oscReceiver); _tuioClient->addTuioListener(this); _tuioClient->connect(); -} +} \ No newline at end of file From 90faf09fa2ef09bbc0651558e28e7dd1f4d460a1 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 12 May 2017 15:27:27 -0600 Subject: [PATCH 095/192] fix .csv print on unit test --- modules/touch/ext/levmarq.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 75be500d68..58e30d9ccd 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -93,7 +93,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq, for (int i = 0; i < npar; ++i) { qs << "q" << i; gs << "g" << i; - ds << "q" << i; + ds << "d" << i; if (i + 1 < npar) { qs << ","; gs << ","; @@ -102,7 +102,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq, } int k = 1; for (int i = 0; i < ny; ++i) { - for (int j = 0; j < ny; ++j) { + for (int j = 0; j < 2; ++j) { ps << "pos" << i << j; if (j + 1 < ny) { ps << ","; From e28897eee71dd0ef46298f8166ade628155d39c9 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 12 May 2017 15:42:47 -0600 Subject: [PATCH 096/192] allow refocus on selected node in case of double tap --- modules/touch/src/TouchInteraction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 9af6f1af03..2aa2456c90 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -68,7 +68,7 @@ TouchInteraction::TouchInteraction() _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 0.25f, 0, 1), _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0008f, 0, 0.001), _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.01f, 0, 0.1), - _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 6, 0, 20), + _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 4, 0, 20), _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.02, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), @@ -470,7 +470,7 @@ void TouchInteraction::computeVelocities(const std::vector& list, co break; } case PICK: { // pick something in the scene as focus node - if (_selected.size() == 1 && _selected.at(0).node != _focusNode) { + if (_selected.size() == 1 && _selected.at(0).node) { setFocusNode(_selected.at(0).node); OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode From 542e4c0fcbbc1911a6770f1af8a26676114b246d Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 12 May 2017 15:55:20 -0600 Subject: [PATCH 097/192] changes during feedback and cleanup --- modules/touch/src/TuioEar.cpp | 14 +++++++++++--- modules/touch/touchmodule.h | 2 +- openspace.cfg | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index b5b4c0e086..7080859936 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -88,9 +88,17 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); _removeList.push_back(tcur->getSessionID()); - if (tcur->getPath().size() < 4 && tcur->getMotionSpeed() < 0.03 && _list.size() == _removeList.size() == 1) { // maybe take away motionspeed - _tapCo = TuioCursor(*tcur); - _tap = true; + + if (!_list.empty()) { + double dist = 0; + for (const TuioPoint& p : tcur->getPath()) { + dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY())); + } + dist /= tcur->getPath().size(); + if (tcur->getPath().size() < 7 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) { + _tapCo = TuioCursor(*tcur); + _tap = true; + } } _mx.unlock(); } diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 763063e88c..4cae20213c 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -32,8 +32,8 @@ namespace openspace { class TouchModule : public OpenSpaceModule { - public: using Point = std::pair; + public: TouchModule(); private: diff --git a/openspace.cfg b/openspace.cfg index dc126d8a42..27dd3511df 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -87,7 +87,7 @@ return { Type = "html", File = "${DOCUMENTATION}/FactoryDocumentation.html" }, - ShutdownCountdown = 3, + ShutdownCountdown = 0, -- OnScreenTextScaling = "framebuffer", -- PerSceneCache = true, -- DisableRenderingOnMaster = true, From 1b1cbcfdfb646fdb6db85e63f94f6c7aa6a41991 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 12 May 2017 16:14:24 -0600 Subject: [PATCH 098/192] fix to panning speed into direct-manipulation issue --- modules/touch/src/TouchInteraction.cpp | 1 + modules/touch/src/TuioEar.cpp | 19 ++++++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 2aa2456c90..3b5a84734d 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -129,6 +129,7 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, // evaluates if current frame is in directTouchMode (will if so be used next frame) if (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()) { // needs better definition? + _vel.pan = glm::dvec2(0.0, 0.0); _directTouchMode = true; } else { diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 7080859936..10f652441e 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -88,17 +88,14 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); _removeList.push_back(tcur->getSessionID()); - - if (!_list.empty()) { - double dist = 0; - for (const TuioPoint& p : tcur->getPath()) { - dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY())); - } - dist /= tcur->getPath().size(); - if (tcur->getPath().size() < 7 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) { - _tapCo = TuioCursor(*tcur); - _tap = true; - } + double dist = 0; + for (const TuioPoint& p : tcur->getPath()) { + dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY())); + } + dist /= tcur->getPath().size(); + if (tcur->getPath().size() < 7 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) { + _tapCo = TuioCursor(*tcur); + _tap = true; } _mx.unlock(); } From 7e1514d165cd7fcc55c83d9a95719ea653aad53f Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 16 May 2017 17:14:19 -0600 Subject: [PATCH 099/192] fix printed name on data --- modules/touch/ext/levmarq.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 58e30d9ccd..82bbd0a85a 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -103,7 +103,8 @@ bool levmarq(int npar, double *par, int ny, double *dysq, int k = 1; for (int i = 0; i < ny; ++i) { for (int j = 0; j < 2; ++j) { - ps << "pos" << i << j; + std::string s = (j == 0) ? "x" : "y"; + ps << "p" << i << s; if (j + 1 < ny) { ps << ","; } From 3a93825979831b44e3c1e599b9cfad202979d9ce Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 16 May 2017 17:15:35 -0600 Subject: [PATCH 100/192] fix to XY-axis issue with zoom/roll, change to three-finger-case --- data/scene/globebrowsing.scene | 6 +- modules/touch/include/TouchInteraction.h | 2 + modules/touch/src/TouchInteraction.cpp | 72 +++++++++++++++--------- openspace.cfg | 4 +- 4 files changed, 51 insertions(+), 33 deletions(-) diff --git a/data/scene/globebrowsing.scene b/data/scene/globebrowsing.scene index 76f358cf2d..2f5bf74957 100644 --- a/data/scene/globebrowsing.scene +++ b/data/scene/globebrowsing.scene @@ -10,10 +10,10 @@ function preInitialization() openspace.spice.loadKernel("${SPICE}/pck00010.tpc") -- For unit test - openspace.time.setTime("2016 SEP 8 23:00:00.500") - openspace.time.togglePause() + --openspace.time.setTime("2016 SEP 8 23:00:00.500") + --openspace.time.togglePause() - --openspace.time.setTime(openspace.time.currentWallTime()) + openspace.time.setTime(openspace.time.currentWallTime()) dofile(openspace.absPath('${SCRIPTS}/bind_common_keys.lua')) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index e75a6c3c7b..2ce7a556a7 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -78,6 +78,7 @@ class TouchInteraction : public properties::PropertyOwner SceneGraphNode* node; double aspectRatio; LMstat stats; + bool onlyPan; }; void updateStateFromInput(const std::vector& list, std::vector& lastProcessed); @@ -107,6 +108,7 @@ class TouchInteraction : public properties::PropertyOwner properties::StringProperty _origin; properties::BoolProperty _lmVerbose; properties::BoolProperty _unitTest; + properties::BoolProperty _onlyPan; // temp properties::IntProperty _maxTapTime; properties::FloatProperty _touchScreenSize; properties::FloatProperty _nodeRadiusThreshold; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 3b5a84734d..3bd752f3d4 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -32,7 +32,7 @@ #include #include #include - +#include #include #include @@ -60,9 +60,10 @@ TouchInteraction::TouchInteraction() _origin("origin", "Origin", ""), _lmVerbose("LM verbose", "Save data from LM algorithm", false), _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), + _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", false), // temp _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), - _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.3f, 0.0f, 1.0f), + _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.038f, 0.0f, 0.1f), _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.004f, 0.0, 0.01), _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 0.25f, 0, 1), @@ -80,6 +81,7 @@ TouchInteraction::TouchInteraction() { addProperty(_lmVerbose); addProperty(_unitTest); + addProperty(_onlyPan); // temp addProperty(_maxTapTime); addProperty(_touchScreenSize); addProperty(_nodeRadiusThreshold); @@ -108,6 +110,7 @@ TouchInteraction::TouchInteraction() // Called each frame if there is any input void TouchInteraction::updateStateFromInput(const std::vector& list, std::vector& lastProcessed) { + ghoul_precondition(!list.empty(), "List must not be empty"); if (_tap) { // check for doubletap if (_time.getSessionTime().getTotalMilliseconds() < _maxTapTime) { _doubleTap = true; @@ -129,7 +132,7 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, // evaluates if current frame is in directTouchMode (will if so be used next frame) if (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()) { // needs better definition? - _vel.pan = glm::dvec2(0.0, 0.0); + //_vel.pan = glm::dvec2(0.0, 0.0); _directTouchMode = true; } else { @@ -144,7 +147,7 @@ bool TouchInteraction::guiMode(const std::vector& list) { glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y)); // mouse pixel position _guiON = OnScreenGUIModule::gui.isEnabled(); _lmstat.verbose = _lmVerbose; - if (_tap && list.size() == 1 && pos.x < _guiButton.value().x && pos.y < _guiButton.value().y) { // pressed invisible button + if (_tap && list.size() == 1 && std::abs(pos.x) < _guiButton.value().x && std::abs(pos.y) < _guiButton.value().y) { // pressed invisible button _guiON = !_guiON; OnScreenGUIModule::gui.setEnabled(_guiON); @@ -161,6 +164,12 @@ bool TouchInteraction::guiMode(const std::vector& list) { // Sets _vel to update _camera according to direct-manipulation (L2 error) void TouchInteraction::directControl(const std::vector& list) { + // Reset old velocities upon new interaction + _vel.orbit = glm::dvec2(0.0, 0.0); + _vel.zoom = 0.0; + _vel.roll = 0.0; + _vel.pan = glm::dvec2(0.0, 0.0); + // Returns the screen point s(xi,par) dependant the transform M(par) and object point xi auto distToMinimize = [](double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); @@ -220,7 +229,6 @@ void TouchInteraction::directControl(const std::vector& list) { } // Update the camera state - // @COMMENT Do you have to make a copy of the camera object here? You are not using it afterwards Camera cam = *(ptr->camera); cam.setPositionVec3(camPos); cam.setRotation(globalCamRot * localCamRot); @@ -245,7 +253,23 @@ void TouchInteraction::directControl(const std::vector& list) { par[i] -= h; der = (f1 - f0) / h; - g[i] = (i > 1 && i < 4) ? der : der / abs(der); + g[i] = der; + } + if (ptr->nDOF == 2) { + for (int i = 0; i < 2; ++i) { + g[i] = g[i]/std::abs(g[i]); + } + } + else if (ptr->nDOF == 6) { + for (int i = 0; i < ptr->nDOF; ++i) { // 3 finger case + //g[i] = (i > 1 && i < 4) ? g[i] : g[i] / std::abs(g[i]); // like it used to be + if (ptr->onlyPan) { // temp for feedback + g[i] = g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan + } + else { + // do nothing - fits fingers well, but is difficult to control + } + } } }; @@ -271,7 +295,7 @@ void TouchInteraction::directControl(const std::vector& list) { screenPoints.push_back(glm::dvec2(2 * (c->getX() - 0.5), -2 * (c->getY() - 0.5))); // normalized -1 to 1 coordinates on screen } //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88, _lmstat }; + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88, _lmstat, _onlyPan }; void* dataPtr = reinterpret_cast(&fData); _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par @@ -285,7 +309,7 @@ void TouchInteraction::directControl(const std::vector& list) { _vel.pan = glm::dvec2(par.at(4), par.at(5)); } } - step(1); + step(1.0); _lastVel = _vel; _vel.orbit = glm::dvec2(0.0, 0.0); _vel.zoom = 0.0; @@ -373,7 +397,7 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { // Interprets the input gesture to a specific interaction int TouchInteraction::interpretInteraction(const std::vector& list, const std::vector& lastProcessed) { - // @COMMENT #include Then you can use ghoul_precondition as an assertion to check if, for example, list is not empty + ghoul_precondition(!list.empty(), "List must not be empty"); double dist = 0; double lastDist = 0; TuioCursor cursor = list.at(0); @@ -591,26 +615,9 @@ void TouchInteraction::unitTest() { //openspace.time.setTime("2016 SEP 8 23:00:00.500") //openspace.time.togglePause() - using namespace glm; // set camera pos and rot - glm::dvec3 camPos = dvec3(26974419543.178154, 76302892465.068359, -127116625827.843369); // chosen world location that fits - _camera->setPositionVec3(camPos); - - glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); - glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); - double angle = glm::angle(camForward, camToFocus); - glm::dvec3 axis = glm::normalize(glm::cross(camForward, camToFocus)); - dquat Q; - Q.x = axis.x * sin(angle / 2.0); - Q.y = axis.y * sin(angle / 2.0); - Q.z = axis.z * sin(angle / 2.0); - Q.w = cos(angle / 2.0); - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - normalize(camToFocus), - normalize(_camera->viewDirectionWorldSpace() + _camera->lookUpVectorWorldSpace())); // To avoid problem with lookup in up direction - dquat globalCamRot = normalize(quat_cast(inverse(lookAtMat))); - _camera->setRotation(globalCamRot * Q); + //_camera->setPositionVec3(glm::dvec3(26974419543.178154, 76302892465.068359, -127116625827.843369)); + //_camera->setRotation(glm::dquat(0.791502, -0.576456, -0.001228, -0.203029)); // set _selected pos and new pos (on screen) std::vector lastFrame = { @@ -635,8 +642,15 @@ void TouchInteraction::unitTest() { // clear everything _selected.clear(); + _vel.orbit = glm::dvec2(0.0, 0.0); + _vel.zoom = 0.0; + _vel.roll = 0.0; + _vel.pan = glm::dvec2(0.0, 0.0); + _lastVel = _vel; _unitTest = false; _lmVerbose = false; + + // could be the camera copy in func } } @@ -653,7 +667,9 @@ void TouchInteraction::decelerate() { // Called if all fingers are off the screen void TouchInteraction::resetAfterInput() { + ghoul_postcondition(_selected.empty(), "Selected list must be empty after reset"); _lmSuccess = true; + //_directTouchMode = false; if (_directTouchMode && _selected.size() > 0) { double spinDelta = _spinSensitivity / OsEng.windowWrapper().averageDeltaTime(); if (glm::length(_lastVel.pan) > _panSpeedThreshold) { // might not be desired diff --git a/openspace.cfg b/openspace.cfg index 27dd3511df..8dbb3803df 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,13 +7,13 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, + --SGCTConfig = sgct.config.single{}, -- Fullscreen mode --SGCTConfig = sgct.config.single{fullScreen=true}, -- A regular 1920x1080 window - --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From 69907fd60c99862f9afd4f1343c95c38cf3b8bcc Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 16 May 2017 18:21:07 -0600 Subject: [PATCH 101/192] nullify roll velocity in onlyPan case --- modules/touch/src/TouchInteraction.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 3bd752f3d4..df422c80cb 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -306,6 +306,9 @@ void TouchInteraction::directControl(const std::vector& list) { _vel.zoom = par.at(2); _vel.roll = par.at(3); if (nDOF > 4) { + if (_onlyPan) { + _vel.roll = 0.0; + } _vel.pan = glm::dvec2(par.at(4), par.at(5)); } } From 63c02a72aee35de064602fefb1b1b02bd5e4dc48 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 11:00:54 -0600 Subject: [PATCH 102/192] build fix --- modules/touch/ext/levmarq.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 82bbd0a85a..2424112886 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -90,7 +90,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq, if (verbose) { std::ostringstream qs, gs, ds, ps, oss; - for (int i = 0; i < npar; ++i) { + for (i = 0; i < npar; ++i) { qs << "q" << i; gs << "g" << i; ds << "d" << i; @@ -101,8 +101,8 @@ bool levmarq(int npar, double *par, int ny, double *dysq, } } int k = 1; - for (int i = 0; i < ny; ++i) { - for (int j = 0; j < 2; ++j) { + for (i = 0; i < ny; ++i) { + for (j = 0; j < 2; ++j) { std::string s = (j == 0) ? "x" : "y"; ps << "p" << i << s; if (j + 1 < ny) { @@ -163,7 +163,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq, printf("\n");*/ std::ostringstream gString, qString, dString, pString, os; - for (int i = 0; i < npar; ++i) { + for (i = 0; i < npar; ++i) { gString << g[i]; qString << par[i]; dString << d[i]; @@ -173,7 +173,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq, dString << ","; } } - for (int i = 0; i < ny; ++i) { + for (i = 0; i < ny; ++i) { pString << lmstat->pos.at(i).x << "," << lmstat->pos.at(i).y; if (i + 1 < ny) { pString << ","; From 22dd7f2fb031e819cdc41f5f2599e9ca48650b93 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 11:10:55 -0600 Subject: [PATCH 103/192] fix to GUI toggle with keyboard+touch inconsistency --- modules/touch/src/TouchInteraction.cpp | 1 + openspace.cfg | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 3bd752f3d4..502d602da3 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -669,6 +669,7 @@ void TouchInteraction::decelerate() { void TouchInteraction::resetAfterInput() { ghoul_postcondition(_selected.empty(), "Selected list must be empty after reset"); _lmSuccess = true; + _guiON = OnScreenGUIModule::gui.isEnabled(); //_directTouchMode = false; if (_directTouchMode && _selected.size() > 0) { double spinDelta = _spinSensitivity / OsEng.windowWrapper().averageDeltaTime(); diff --git a/openspace.cfg b/openspace.cfg index 8dbb3803df..6a24c06f5d 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -10,10 +10,10 @@ return { --SGCTConfig = sgct.config.single{}, -- Fullscreen mode - --SGCTConfig = sgct.config.single{fullScreen=true}, + SGCTConfig = sgct.config.single{fullScreen=true}, -- A regular 1920x1080 window - SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From 7f82454114ee4c05d4a0d9c91ba7d6f824acde0e Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 13:09:15 -0600 Subject: [PATCH 104/192] small clean of LMA --- modules/touch/ext/levmarq.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 2424112886..c0012d0f8e 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -203,7 +203,7 @@ bool levmarq(int npar, double *par, int ny, double *dysq, lmstat->data = data; // deallocate the arrays - for (int i = 0; i < npar; i++) { + for (i = 0; i < npar; i++) { delete[] h[i]; delete[] ch[i]; } @@ -237,7 +237,7 @@ double error_func(double *par, int ny, double *dysq, // solve Ax=b for a symmetric positive-definite matrix A using the Cholesky decomposition A=LL^T, L is passed in "l", elements above the diagonal are ignored. void solve_axb_cholesky(int n, double** l, double* x, double* b) { // n = npar, l = ch, x = delta (solution), b = d (func(par, x, fdata) * g[i]); - int i,j; + int i, j; double sum; // solve L*y = b for y (where x[] is used to store y) for (i = 0; i < n; i++) { @@ -259,7 +259,7 @@ void solve_axb_cholesky(int n, double** l, double* x, double* b) { // n = npar, // symmetric, positive-definite matrix "a" and returns its (lower-triangular) Cholesky factor in "l", if l=a the decomposition is performed in place, elements above the diagonal are ignored. int cholesky_decomp(int n, double** l, double** a) { - int i,j,k; + int i, j, k; double sum; for (i = 0; i < n; i++) { for (j = 0; j < i; j++) { From 92274563a479c172eb3341e9f6de41f4002787e9 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 13:11:15 -0600 Subject: [PATCH 105/192] removed finger scaling on zoom/roll, reintroduced roll interpret with all fingers, rescaled sensitivities to fit new method, fix build issue with ghoul_condition --- modules/touch/include/TouchInteraction.h | 5 +- modules/touch/src/TouchInteraction.cpp | 84 ++++++++++++++---------- openspace.cfg | 4 +- 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 2ce7a556a7..3f4bc360a2 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -106,12 +106,13 @@ class TouchInteraction : public properties::PropertyOwner // Property variables properties::StringProperty _origin; - properties::BoolProperty _lmVerbose; properties::BoolProperty _unitTest; properties::BoolProperty _onlyPan; // temp properties::IntProperty _maxTapTime; properties::FloatProperty _touchScreenSize; + properties::FloatProperty _tapZoomFactor; properties::FloatProperty _nodeRadiusThreshold; + properties::FloatProperty _rollAngleThreshold; properties::FloatProperty _orbitSpeedThreshold; properties::FloatProperty _panSpeedThreshold; properties::FloatProperty _spinSensitivity; @@ -139,6 +140,8 @@ class TouchInteraction : public properties::PropertyOwner std::vector _selected; LMstat _lmstat; glm::dquat _toSlerp; + glm::dvec3 _centroid; + }; } // openspace namespace diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index ed37b1177a..7516aa8118 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -58,33 +58,36 @@ namespace openspace { TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), - _lmVerbose("LM verbose", "Save data from LM algorithm", false), _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", false), // temp _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), + _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.2, 0.0, 1.0), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), + _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.019f, 0.0f, 0.05f), _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.038f, 0.0f, 0.1f), _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.004f, 0.0, 0.01), _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 0.25f, 0, 1), - _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0008f, 0, 0.001), + _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0005f, 0, 0.001), _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.01f, 0, 0.1), _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 4, 0, 20), _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.02, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) }, - _sensitivity{glm::dvec2(0.1, 0.1778), 110, 22, glm::dvec2(0.1, 0.1778) }, + _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) }, + _centroid{ glm::dvec3(0.0) }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { - addProperty(_lmVerbose); addProperty(_unitTest); addProperty(_onlyPan); // temp addProperty(_maxTapTime); addProperty(_touchScreenSize); + addProperty(_tapZoomFactor); addProperty(_nodeRadiusThreshold); + addProperty(_rollAngleThreshold); addProperty(_orbitSpeedThreshold); addProperty(_panSpeedThreshold); addProperty(_spinSensitivity); @@ -110,7 +113,7 @@ TouchInteraction::TouchInteraction() // Called each frame if there is any input void TouchInteraction::updateStateFromInput(const std::vector& list, std::vector& lastProcessed) { - ghoul_precondition(!list.empty(), "List must not be empty"); + //ghoul_precondition(!list.empty(), "List must not be empty"); if (_tap) { // check for doubletap if (_time.getSessionTime().getTotalMilliseconds() < _maxTapTime) { _doubleTap = true; @@ -146,7 +149,6 @@ bool TouchInteraction::guiMode(const std::vector& list) { glm::ivec2 res = wrapper.currentWindowSize(); glm::dvec2 pos = glm::vec2(list.at(0).getScreenX(res.x), list.at(0).getScreenY(res.y)); // mouse pixel position _guiON = OnScreenGUIModule::gui.isEnabled(); - _lmstat.verbose = _lmVerbose; if (_tap && list.size() == 1 && std::abs(pos.x) < _guiButton.value().x && std::abs(pos.y) < _guiButton.value().y) { // pressed invisible button _guiON = !_guiON; OnScreenGUIModule::gui.setEnabled(_guiON); @@ -321,7 +323,7 @@ void TouchInteraction::directControl(const std::vector& list) { } // debugging - if (_lmVerbose) { + if (_lmstat.verbose) { /*std::cout << _lmstat.data; std::ostringstream os; for (int i = 0; i < nDOF; ++i) { @@ -400,7 +402,11 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { // Interprets the input gesture to a specific interaction int TouchInteraction::interpretInteraction(const std::vector& list, const std::vector& lastProcessed) { - ghoul_precondition(!list.empty(), "List must not be empty"); + //ghoul_precondition(!list.empty(), "List must not be empty"); + _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + + // see if the distance between fingers changed double dist = 0; double lastDist = 0; TuioCursor cursor = list.at(0); @@ -413,7 +419,7 @@ int TouchInteraction::interpretInteraction(const std::vector& list, lastDist += glm::length(glm::dvec2(p.second.getX(), p.second.getY()) - glm::dvec2(point.getX(), point.getY())); point = p.second; } - + // find the slowest moving finger double minDiff = 1000; int id = 0; for (const TuioCursor& c : list) { @@ -428,6 +434,23 @@ int TouchInteraction::interpretInteraction(const std::vector& list, id = c.getSessionID(); } } + // find if all fingers angles are high + double rollOn = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { + TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; + double res = 0.0; + double lastAngle = point.getAngle(_centroid.x, _centroid.y); + double currentAngle = c.getAngle(_centroid.x, _centroid.y); + if (lastAngle > currentAngle + 1.5 * M_PI) + res = currentAngle + (2 * M_PI - lastAngle); + else if (currentAngle > lastAngle + 1.5 * M_PI) + res = (2 * M_PI - currentAngle) + lastAngle; + else + res = currentAngle - lastAngle; + if (std::abs(res) < _rollAngleThreshold) + return 1000.0; + else + return (diff + res); + }); if (_doubleTap) { return PICK; @@ -439,8 +462,8 @@ int TouchInteraction::interpretInteraction(const std::vector& list, if (std::abs(dist - lastDist) / list.at(0).getMotionSpeed() < _interpretPan && list.size() == 3) { // if distance between fingers is constant we have panning return PAN; } - else if (list.size() > 1 && std::abs(minDiff) < _inputStillThreshold) { // if one finger is 'still' (epsilon) and another moving, we have roll - return ROLL; + else if (std::abs(minDiff) < _inputStillThreshold || std::abs(rollOn) < 100.0) { // if one finger is 'still' (epsilon) and another moving, we have roll + return ROLL; // also interpret if angles are high } else { return PINCH; @@ -451,13 +474,8 @@ int TouchInteraction::interpretInteraction(const std::vector& list, // Calculate how much interpreted interaction should change the camera state (based on _vel) void TouchInteraction::computeVelocities(const std::vector& list, const std::vector& lastProcessed) { TuioCursor cursor = list.at(0); - glm::dvec3 centroid; int action = interpretInteraction(list, lastProcessed); - if (action != ROT || action != PICK) { - centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); - centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - } switch (action) { case ROT: { // add rotation velocity @@ -466,22 +484,22 @@ void TouchInteraction::computeVelocities(const std::vector& list, co } case PINCH: { // add zooming velocity double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { - return d + c.getDistance(centroid.x, centroid.y); - }); + return d + c.getDistance(_centroid.x, _centroid.y); + }) / list.size(); double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { - return d + p.second.getDistance(centroid.x, centroid.y); - }); + return d + p.second.getDistance(_centroid.x, _centroid.y); + }) / lastProcessed.size(); - double zoomFactor = (distance - lastDistance) * glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()); - _vel.zoom += zoomFactor * _sensitivity.zoom / _touchScreenSize.value(); + double zoomFactor = (distance - lastDistance) * (glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere()); + _vel.zoom += zoomFactor * _sensitivity.zoom * std::max(_touchScreenSize.value() * 0.1, 1.0); break; } case ROLL: { // add global roll rotation velocity double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = diff; - double lastAngle = point.getAngle(centroid.x, centroid.y); - double currentAngle = c.getAngle(centroid.x, centroid.y); + double lastAngle = point.getAngle(_centroid.x, _centroid.y); + double currentAngle = c.getAngle(_centroid.x, _centroid.y); if (lastAngle > currentAngle + 1.5 * M_PI) res += currentAngle + (2 * M_PI - lastAngle); else if (currentAngle > lastAngle + 1.5 * M_PI) @@ -489,8 +507,9 @@ void TouchInteraction::computeVelocities(const std::vector& list, co else res += currentAngle - lastAngle; return res; - }); - _vel.roll += -rollFactor * _sensitivity.roll / _touchScreenSize.value(); + }) / list.size(); + + _vel.roll += -rollFactor * _sensitivity.roll; break; } case PAN: { // add local rotation velocity @@ -515,13 +534,7 @@ void TouchInteraction::computeVelocities(const std::vector& list, co } else { // should zoom in to current but not too much double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); - double startDecline = _focusNode->boundingSphere() / (0.15 * _projectionScaleFactor); - double factor = 2.0; - if (dist < startDecline) { // double-check this - factor = 1.0 + std::pow(dist / startDecline, 2); - } - double response = _focusNode->boundingSphere() / (factor * _currentRadius * _projectionScaleFactor); - _vel.zoom = (_sensitivity.zoom / _touchScreenSize.value()) * response; + _vel.zoom = (_sensitivity.zoom * std::max(_touchScreenSize.value() * 0.1, 1.0)) * _tapZoomFactor * dist; } break; } @@ -613,7 +626,7 @@ void TouchInteraction::step(double dt) { void TouchInteraction::unitTest() { if (_unitTest) { - _lmVerbose = _lmstat.verbose = true; + _lmstat.verbose = true; // time set and paused in .scene file //openspace.time.setTime("2016 SEP 8 23:00:00.500") //openspace.time.togglePause() @@ -651,7 +664,6 @@ void TouchInteraction::unitTest() { _vel.pan = glm::dvec2(0.0, 0.0); _lastVel = _vel; _unitTest = false; - _lmVerbose = false; // could be the camera copy in func } @@ -670,7 +682,7 @@ void TouchInteraction::decelerate() { // Called if all fingers are off the screen void TouchInteraction::resetAfterInput() { - ghoul_postcondition(_selected.empty(), "Selected list must be empty after reset"); + //ghoul_postcondition(_selected.empty(), "Selected list must be empty after reset"); _lmSuccess = true; _guiON = OnScreenGUIModule::gui.isEnabled(); //_directTouchMode = false; diff --git a/openspace.cfg b/openspace.cfg index 6a24c06f5d..8dbb3803df 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -10,10 +10,10 @@ return { --SGCTConfig = sgct.config.single{}, -- Fullscreen mode - SGCTConfig = sgct.config.single{fullScreen=true}, + --SGCTConfig = sgct.config.single{fullScreen=true}, -- A regular 1920x1080 window - --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From d626684d5ffd1299607f22dca03148c98418a657 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 14:49:27 -0600 Subject: [PATCH 106/192] dynamic step size in gradient LMA is now based on planet size as well to make for smooth interaction on huge planets --- modules/touch/src/TouchInteraction.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 7516aa8118..e0c5adcc93 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -245,11 +245,16 @@ void TouchInteraction::directControl(const std::vector& list) { FunctionData* ptr = reinterpret_cast(fdata); glm::dvec3 camPos = ptr->camera->positionVec3(); glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); - double h = 1e-11 * glm::distance(camPos, selectedPoint); + double h = 1e-11 * glm::distance(camPos, selectedPoint), hZoom = 1e-4; double der, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); + double planetScale = ptr->node->boundingSphere() / 1e7; + if (planetScale > 1.0) { + hZoom *= planetScale; + h *= (planetScale / std::pow(10, fmod(planetScale,10.0) / 2.0)); + } for (int i = 0; i < ptr->nDOF; ++i) { - h = (i == 2) ? 1e-4 : h; // the 'zoom'-DOF is so big a smaller step creates NAN + h = (i == 2) ? hZoom : h; // the 'zoom'-DOF is so big a smaller step creates NAN par[i] += h; f1 = ptr->distToMinimize(par, x, fdata, lmstat); par[i] -= h; @@ -301,7 +306,7 @@ void TouchInteraction::directControl(const std::vector& list) { void* dataPtr = reinterpret_cast(&fData); _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - + std::cout << node->boundingSphere() << "\n"; if (_lmSuccess && !_unitTest) { // if good values were found set new camera state _vel.orbit = glm::dvec2(par.at(0), par.at(1)); if (nDOF > 2) { From bbccda7d8c41adb2d7d99b2f0ef14ce4d6af9e81 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 14:49:50 -0600 Subject: [PATCH 107/192] onlyPan on by default for easier direct-manipulation with 3+ fingers --- modules/touch/src/TouchInteraction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index e0c5adcc93..fe32529565 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -59,7 +59,7 @@ TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), - _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", false), // temp + _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", true), // temp _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.2, 0.0, 1.0), From 195dd2e1b5b264037bd2f2ff131d66e25775b89a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 15:15:55 -0600 Subject: [PATCH 108/192] fix bug that caused slerp time to be too quick --- modules/touch/src/TouchInteraction.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index fe32529565..2ac93005a4 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -70,7 +70,7 @@ TouchInteraction::TouchInteraction() _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 0.25f, 0, 1), _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0005f, 0, 0.001), _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.01f, 0, 0.1), - _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 4, 0, 20), + _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 1, 0, 5), _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.02, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), @@ -306,7 +306,7 @@ void TouchInteraction::directControl(const std::vector& list) { void* dataPtr = reinterpret_cast(&fData); _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - std::cout << node->boundingSphere() << "\n"; + if (_lmSuccess && !_unitTest) { // if good values were found set new camera state _vel.orbit = glm::dvec2(par.at(0), par.at(1)); if (nDOF > 2) { @@ -585,8 +585,9 @@ void TouchInteraction::step(double dt) { // if we have chosen a new focus node if (_slerpdT < _slerpTime) { + std::cout << "Time it should take: " << _slerpTime << ", slerped time: " << _slerpdT << ", interpolation: " << _slerpdT / _slerpTime << "\n"; _slerpdT += dt; - localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime); + localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime * 0.018); } } { // Orbit (global rotation) From b7da01f322412faf153ec3cd2c5fc24d0558d38a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 15:17:17 -0600 Subject: [PATCH 109/192] remove debug print --- modules/touch/src/TouchInteraction.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 2ac93005a4..8bc50d7bd5 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -585,7 +585,6 @@ void TouchInteraction::step(double dt) { // if we have chosen a new focus node if (_slerpdT < _slerpTime) { - std::cout << "Time it should take: " << _slerpTime << ", slerped time: " << _slerpdT << ", interpolation: " << _slerpdT / _slerpTime << "\n"; _slerpdT += dt; localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime * 0.018); } From bae7110f300541347f784970ec13e3116f2745a2 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 17 May 2017 16:55:23 -0600 Subject: [PATCH 110/192] new ideas on how 3+ fingers should work, needs feedback --- ext/ghoul | 2 +- modules/touch/src/TouchInteraction.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index 894358db7a..20131b6897 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 894358db7a1e15d7ae81a251aa2062ae8a48fa87 +Subproject commit 20131b68975456d4a90b5cf997dd8f10179a3a31 diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 8bc50d7bd5..9f3e1c7261 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -269,12 +269,14 @@ void TouchInteraction::directControl(const std::vector& list) { } else if (ptr->nDOF == 6) { for (int i = 0; i < ptr->nDOF; ++i) { // 3 finger case - //g[i] = (i > 1 && i < 4) ? g[i] : g[i] / std::abs(g[i]); // like it used to be + + if (ptr->onlyPan) { // temp for feedback g[i] = g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan } else { // do nothing - fits fingers well, but is difficult to control + //g[i] = (i < 4) ? g[i] : g[i] / std::abs(g[i]); // like it used to be, mute roll or not? } } } @@ -539,7 +541,7 @@ void TouchInteraction::computeVelocities(const std::vector& list, co } else { // should zoom in to current but not too much double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); - _vel.zoom = (_sensitivity.zoom * std::max(_touchScreenSize.value() * 0.1, 1.0)) * _tapZoomFactor * dist; + _vel.zoom = (_sensitivity.zoom * std::max(_touchScreenSize.value() * 0.1, 1.0)) * _tapZoomFactor * dist; // this should not be based on dt } break; } @@ -586,7 +588,7 @@ void TouchInteraction::step(double dt) { // if we have chosen a new focus node if (_slerpdT < _slerpTime) { _slerpdT += dt; - localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime * 0.018); + localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime * 0.025); } } { // Orbit (global rotation) From 612b207d19f34f32f4c3736a02dc507c5cdda045 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 18 May 2017 19:19:26 -0600 Subject: [PATCH 111/192] mute mouse input when we have touch input (for feedback on linux) --- modules/touch/ext/levmarq.cpp | 1 - modules/touch/include/TouchInteraction.h | 2 + modules/touch/src/TouchInteraction.cpp | 11 +- modules/touch/touchmodule.cpp | 4 +- openspace.cfg | 4 +- src/interaction/interactionmode.cpp | 125 ++++++++++++----------- 6 files changed, 77 insertions(+), 70 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index c0012d0f8e..89ee28bd2a 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -100,7 +100,6 @@ bool levmarq(int npar, double *par, int ny, double *dysq, ds << ","; } } - int k = 1; for (i = 0; i < ny; ++i) { for (j = 0; j < 2; ++j) { std::string s = (j == 0) ? "x" : "y"; diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 3f4bc360a2..880405b5d5 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -86,6 +86,7 @@ class TouchInteraction : public properties::PropertyOwner void unitTest(); void resetAfterInput(); void tap(); + void touchActive(bool active); // Get & Setters Camera* getCamera(); @@ -108,6 +109,7 @@ class TouchInteraction : public properties::PropertyOwner properties::StringProperty _origin; properties::BoolProperty _unitTest; properties::BoolProperty _onlyPan; // temp + properties::BoolProperty _touchActive; properties::IntProperty _maxTapTime; properties::FloatProperty _touchScreenSize; properties::FloatProperty _tapZoomFactor; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 9f3e1c7261..16b2ee2402 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -60,6 +60,7 @@ TouchInteraction::TouchInteraction() _origin("origin", "Origin", ""), _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", true), // temp + _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.2, 0.0, 1.0), @@ -81,6 +82,8 @@ TouchInteraction::TouchInteraction() _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { + addProperty(_touchActive); + addProperty(_unitTest); addProperty(_onlyPan); // temp addProperty(_maxTapTime); @@ -158,8 +161,7 @@ bool TouchInteraction::guiMode(const std::vector& list) { static_cast(100 * (pos.x / _guiButton.value().x)) << "%, " << static_cast(100 * (pos.y / _guiButton.value().y)) << "%)\n"); } else if (_guiON) { - uint32_t action = (_tap) ? 0 : 1; - OnScreenGUIModule::touchInput = { _guiON, pos, action }; + OnScreenGUIModule::touchInput = { _guiON, pos, 1 }; } return _guiON; // return if consumed } @@ -269,8 +271,6 @@ void TouchInteraction::directControl(const std::vector& list) { } else if (ptr->nDOF == 6) { for (int i = 0; i < ptr->nDOF; ++i) { // 3 finger case - - if (ptr->onlyPan) { // temp for feedback g[i] = g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan } @@ -719,6 +719,9 @@ void TouchInteraction::resetAfterInput() { void TouchInteraction::tap() { _tap = true; } +void TouchInteraction::touchActive(bool active) { + _touchActive = active; +} // Get & Setters Camera* TouchInteraction::getCamera() { diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index d580835890..d5613b9994 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -50,6 +50,7 @@ bool TouchModule::hasNewInput() { // Get new input from listener listOfContactPoints = ear.getInput(); ear.clearInput(); + touch.touchActive(!listOfContactPoints.empty()); // Erase old input id's that no longer exists lastProcessed.erase( @@ -98,7 +99,7 @@ bool TouchModule::hasNewInput() { } TouchModule::TouchModule() - : OpenSpaceModule("Touch") + : OpenSpaceModule("Touch") { addPropertySubOwner(touch); @@ -124,7 +125,6 @@ TouchModule::TouchModule() touch.step(OsEng.windowWrapper().deltaTime()); } ); - } } // namespace openspace diff --git a/openspace.cfg b/openspace.cfg index 8dbb3803df..27dd3511df 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,13 +7,13 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - --SGCTConfig = sgct.config.single{}, + SGCTConfig = sgct.config.single{}, -- Fullscreen mode --SGCTConfig = sgct.config.single{fullScreen=true}, -- A regular 1920x1080 window - SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, diff --git a/src/interaction/interactionmode.cpp b/src/interaction/interactionmode.cpp index 0975c8bc49..64354985c3 100644 --- a/src/interaction/interactionmode.cpp +++ b/src/interaction/interactionmode.cpp @@ -292,74 +292,77 @@ OrbitalInteractionMode::MouseStates::MouseStates(double sensitivity, double velo } void OrbitalInteractionMode::MouseStates::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) { - glm::dvec2 mousePosition = inputState.getMousePosition(); + ghoul::any t = property("Global Properties.Touch.TouchInteraction.TouchEvents")->get(); + if (!*(ghoul::any_cast(&t))) { + glm::dvec2 mousePosition = inputState.getMousePosition(); - bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); - bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2); - bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3); - bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl); - bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift); - - // Update the mouse states - if (button1Pressed && !keyShiftPressed) { - if (keyCtrlPressed) { - glm::dvec2 mousePositionDelta = - _localRotationMouseState.previousPosition - mousePosition; - _localRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); + bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); + bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2); + bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3); + bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl); + bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift); - _globalRotationMouseState.previousPosition = mousePosition; - _globalRotationMouseState.velocity.decelerate(deltaTime); - } - else { - glm::dvec2 mousePositionDelta = - _globalRotationMouseState.previousPosition - mousePosition; - _globalRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); + // Update the mouse states + if (button1Pressed && !keyShiftPressed) { + if (keyCtrlPressed) { + glm::dvec2 mousePositionDelta = + _localRotationMouseState.previousPosition - mousePosition; + _localRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - _localRotationMouseState.previousPosition = mousePosition; - _localRotationMouseState.velocity.decelerate(deltaTime); - } - } - else { // !button1Pressed - _localRotationMouseState.previousPosition = mousePosition; - _localRotationMouseState.velocity.decelerate(deltaTime); + _globalRotationMouseState.previousPosition = mousePosition; + _globalRotationMouseState.velocity.decelerate(deltaTime); + } + else { + glm::dvec2 mousePositionDelta = + _globalRotationMouseState.previousPosition - mousePosition; + _globalRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - _globalRotationMouseState.previousPosition = mousePosition; - _globalRotationMouseState.velocity.decelerate(deltaTime); - } - if (button2Pressed) { - glm::dvec2 mousePositionDelta = - _truckMovementMouseState.previousPosition - mousePosition; - _truckMovementMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - } - else { // !button2Pressed - _truckMovementMouseState.previousPosition = mousePosition; - _truckMovementMouseState.velocity.decelerate(deltaTime); - } - if (button3Pressed || (keyShiftPressed && button1Pressed)) { - if (keyCtrlPressed) { - glm::dvec2 mousePositionDelta = - _localRollMouseState.previousPosition - mousePosition; - _localRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); + _localRotationMouseState.previousPosition = mousePosition; + _localRotationMouseState.velocity.decelerate(deltaTime); + } + } + else { // !button1Pressed + _localRotationMouseState.previousPosition = mousePosition; + _localRotationMouseState.velocity.decelerate(deltaTime); - _globalRollMouseState.previousPosition = mousePosition; - _globalRollMouseState.velocity.decelerate(deltaTime); - } - else { - glm::dvec2 mousePositionDelta = - _globalRollMouseState.previousPosition - mousePosition; - _globalRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); + _globalRotationMouseState.previousPosition = mousePosition; + _globalRotationMouseState.velocity.decelerate(deltaTime); + } + if (button2Pressed) { + glm::dvec2 mousePositionDelta = + _truckMovementMouseState.previousPosition - mousePosition; + _truckMovementMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); + } + else { // !button2Pressed + _truckMovementMouseState.previousPosition = mousePosition; + _truckMovementMouseState.velocity.decelerate(deltaTime); + } + if (button3Pressed || (keyShiftPressed && button1Pressed)) { + if (keyCtrlPressed) { + glm::dvec2 mousePositionDelta = + _localRollMouseState.previousPosition - mousePosition; + _localRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - _localRollMouseState.previousPosition = mousePosition; - _localRollMouseState.velocity.decelerate(deltaTime); - } - } - else { // !button3Pressed - _globalRollMouseState.previousPosition = mousePosition; - _globalRollMouseState.velocity.decelerate(deltaTime); + _globalRollMouseState.previousPosition = mousePosition; + _globalRollMouseState.velocity.decelerate(deltaTime); + } + else { + glm::dvec2 mousePositionDelta = + _globalRollMouseState.previousPosition - mousePosition; + _globalRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - _localRollMouseState.previousPosition = mousePosition; - _localRollMouseState.velocity.decelerate(deltaTime); - } + _localRollMouseState.previousPosition = mousePosition; + _localRollMouseState.velocity.decelerate(deltaTime); + } + } + else { // !button3Pressed + _globalRollMouseState.previousPosition = mousePosition; + _globalRollMouseState.velocity.decelerate(deltaTime); + + _localRollMouseState.previousPosition = mousePosition; + _localRollMouseState.velocity.decelerate(deltaTime); + } + } } void OrbitalInteractionMode::MouseStates::setRotationalFriction(double friction) { From 202b31e7d11f73017f2f9d25d3a60384952c07f9 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 19 May 2017 10:32:42 -0600 Subject: [PATCH 112/192] decelerate is now called in a user chosen constant frequency, changed some minor default sensitivities --- modules/touch/include/TouchInteraction.h | 4 +++- modules/touch/src/TouchInteraction.cpp | 30 ++++++++++++++---------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 880405b5d5..6d9cb4ac49 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -100,7 +100,7 @@ class TouchInteraction : public properties::PropertyOwner void findSelectedNode(const std::vector& list); int interpretInteraction(const std::vector& list, const std::vector& lastProcessed); void computeVelocities(const std::vector& list, const std::vector& lastProcessed); - void decelerate(); + void decelerate(double dt); Camera* _camera; SceneGraphNode* _focusNode = nullptr; @@ -111,6 +111,7 @@ class TouchInteraction : public properties::PropertyOwner properties::BoolProperty _onlyPan; // temp properties::BoolProperty _touchActive; properties::IntProperty _maxTapTime; + properties::IntProperty _deceleratesPerSecond; properties::FloatProperty _touchScreenSize; properties::FloatProperty _tapZoomFactor; properties::FloatProperty _nodeRadiusThreshold; @@ -132,6 +133,7 @@ class TouchInteraction : public properties::PropertyOwner double _projectionScaleFactor; double _currentRadius; double _slerpdT; + double _timeSlack; int _numOfTests; TUIO::TuioTime _time; bool _directTouchMode; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 16b2ee2402..5ff58c8ed3 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -62,8 +62,9 @@ TouchInteraction::TouchInteraction() _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", true), // temp _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), + _deceleratesPerSecond("Decelerates per second", "Deceleration rate of velocity, times per second", 240, 60, 300), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), - _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.2, 0.0, 1.0), + _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.1, 0.0, 0.5), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.019f, 0.0f, 0.05f), _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.038f, 0.0f, 0.1f), @@ -79,14 +80,15 @@ TouchInteraction::TouchInteraction() _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) }, _centroid{ glm::dvec3(0.0) }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, + _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack { 0.0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { - addProperty(_touchActive); + addProperty(_touchActive); // hide addProperty(_unitTest); addProperty(_onlyPan); // temp addProperty(_maxTapTime); + addProperty(_deceleratesPerSecond); addProperty(_touchScreenSize); addProperty(_tapZoomFactor); addProperty(_nodeRadiusThreshold); @@ -588,7 +590,7 @@ void TouchInteraction::step(double dt) { // if we have chosen a new focus node if (_slerpdT < _slerpTime) { _slerpdT += dt; - localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime * 0.025); + localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime); } } { // Orbit (global rotation) @@ -621,7 +623,7 @@ void TouchInteraction::step(double dt) { } } - decelerate(); + decelerate(dt); // Update the camera state _camera->setPositionVec3(camPos); _camera->setRotation(globalCamRot * localCamRot); @@ -677,14 +679,18 @@ void TouchInteraction::unitTest() { } // Decelerate velocities (set 0 for directTouch) -void TouchInteraction::decelerate() { - if (!_directTouchMode && _currentRadius > _nodeRadiusThreshold && _vel.zoom > _focusNode->boundingSphere()) { // check for velocity speed too - _vel.zoom *= (1 - 2*_friction.value().y); +void TouchInteraction::decelerate(double dt) { + double frequency = 1.0 / _deceleratesPerSecond; + int times = (dt + _timeSlack) / frequency; + _timeSlack = fmod((dt + _timeSlack), frequency); + + if (!_directTouchMode && _currentRadius > _nodeRadiusThreshold && _vel.zoom > _focusNode->boundingSphere()) { + _vel.zoom *= std::pow(1 - 2 * _friction.value().y, times); } - _vel.orbit *= (1 - _friction.value().x); - _vel.zoom *= (1 - _friction.value().y); - _vel.roll *= (1 - _friction.value().z); - _vel.pan *= (1 - _friction.value().w); + _vel.orbit *= std::pow(1 - _friction.value().x, times); + _vel.zoom *= std::pow(1 - _friction.value().y, times); + _vel.roll *= std::pow(1 - _friction.value().z, times); + _vel.pan *= std::pow(1 - _friction.value().w, times); } // Called if all fingers are off the screen From a230fbeea41e8891c4a3c7d2e1398c355479c6cc Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 19 May 2017 10:50:06 -0600 Subject: [PATCH 113/192] added a reset to default option on properties to the gui --- modules/touch/include/TouchInteraction.h | 2 ++ modules/touch/src/TouchInteraction.cpp | 27 +++++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 6d9cb4ac49..4552addd3d 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -101,6 +101,7 @@ class TouchInteraction : public properties::PropertyOwner int interpretInteraction(const std::vector& list, const std::vector& lastProcessed); void computeVelocities(const std::vector& list, const std::vector& lastProcessed); void decelerate(double dt); + void resetToDefault(); Camera* _camera; SceneGraphNode* _focusNode = nullptr; @@ -110,6 +111,7 @@ class TouchInteraction : public properties::PropertyOwner properties::BoolProperty _unitTest; properties::BoolProperty _onlyPan; // temp properties::BoolProperty _touchActive; + properties::BoolProperty _reset; properties::IntProperty _maxTapTime; properties::IntProperty _deceleratesPerSecond; properties::FloatProperty _touchScreenSize; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 5ff58c8ed3..54570be8af 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -61,6 +61,7 @@ TouchInteraction::TouchInteraction() _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", true), // temp _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), + _reset("Default Values", "Reset all properties to default", false), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _deceleratesPerSecond("Decelerates per second", "Deceleration rate of velocity, times per second", 240, 60, 300), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), @@ -83,10 +84,11 @@ TouchInteraction::TouchInteraction() _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack { 0.0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { - addProperty(_touchActive); // hide + addProperty(_touchActive); // how do i hide this? addProperty(_unitTest); addProperty(_onlyPan); // temp + addProperty(_reset); addProperty(_maxTapTime); addProperty(_deceleratesPerSecond); addProperty(_touchScreenSize); @@ -630,6 +632,9 @@ void TouchInteraction::step(double dt) { _tap = false; _doubleTap = false; + if (_reset) { + resetToDefault(); + } } } @@ -722,6 +727,26 @@ void TouchInteraction::resetAfterInput() { _selected.clear(); // should clear if no longer have a direct-touch input } +void TouchInteraction::resetToDefault() { + _unitTest.set(false); + _onlyPan.set(true); // temp + _reset.set(false); + _maxTapTime.set(300); + _deceleratesPerSecond.set(240); + _touchScreenSize.set(55.0f); + _tapZoomFactor.set(0.1f); + _nodeRadiusThreshold.set(0.2f); + _rollAngleThreshold.set(0.019f); + _orbitSpeedThreshold.set(0.038f); + _panSpeedThreshold.set(0.004f); + _spinSensitivity.set(0.25f); + _inputStillThreshold.set(0.0005f); + _interpretPan.set(0.01f); + _slerpTime.set(1.0f); + _guiButton.set(glm::ivec2(32, 64)); + _friction.set(glm::vec4(0.01, 0.02, 0.02, 0.02)); +} + void TouchInteraction::tap() { _tap = true; } From 0a1cd285a32523a46533a4f48f3ecdc855728407 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 19 May 2017 13:04:28 -0600 Subject: [PATCH 114/192] merge fix --- src/interaction/interactionhandler.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp index f95ba0349d..82d8311d1a 100644 --- a/src/interaction/interactionhandler.cpp +++ b/src/interaction/interactionhandler.cpp @@ -288,10 +288,6 @@ Camera* InteractionHandler::camera() const { return _camera; } -std::shared_ptr InteractionHandler::interactionmode() { - return _currentInteractionMode; -} - const InputState& InteractionHandler::inputState() const { return *_inputState; } From 3386b5906f7a12a418272269a4822e5cc686c6cf Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 19 May 2017 14:00:55 -0600 Subject: [PATCH 115/192] include scene.h --- modules/touch/src/TouchInteraction.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 54570be8af..b15d098b53 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -356,7 +357,7 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { for (std::string name : selectables) if (node->name() == name) selectableNodes.push_back(node); - + //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); // @COMMENT ^_^ double aspectRatio = 1.88; //res.x/res.y; @@ -383,8 +384,6 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { d -= sqrt(root); glm::dvec3 intersectionPoint = camPos + d * raytrace; glm::dvec3 pointInModelView = glm::inverse(node->rotationMatrix()) * (intersectionPoint - node->worldPosition()); - //double theta = atan(pointInModelView.y / pointInModelView.x); - //double phi = atan(glm::length(glm::dvec2(pointInModelView.x, pointInModelView.y)) / pointInModelView.z); // Add id, node and surface coordinates to the selected list std::vector::iterator oldNode = find_if(newSelected.begin(), newSelected.end(), [id](SelectedBody s) { return s.id == id; }); From f8b931041625ebeededd7d3445446fa92d25fe06 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 23 May 2017 17:10:04 -0600 Subject: [PATCH 116/192] first pass on gradient step size that works with 1m - 1e10m --- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 65 ++++++++++++++++-------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 4552addd3d..1f0aee5b9f 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -78,7 +78,8 @@ class TouchInteraction : public properties::PropertyOwner SceneGraphNode* node; double aspectRatio; LMstat stats; - bool onlyPan; + bool onlyPan; // temp + double objectScreenRadius; }; void updateStateFromInput(const std::vector& list, std::vector& lastProcessed); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index b15d098b53..46bb6494dc 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -69,11 +69,11 @@ TouchInteraction::TouchInteraction() _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.1, 0.0, 0.5), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.019f, 0.0f, 0.05f), - _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.038f, 0.0f, 0.1f), - _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.004f, 0.0, 0.01), - _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 0.25f, 0, 1), + _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.005f, 0.0f, 0.01f), + _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.0005f, 0.0, 0.01), + _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 1.0f, 0, 2), _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0005f, 0, 0.001), - _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.01f, 0, 0.1), + _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.015f, 0, 0.1), _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 1, 0, 5), _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.02, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), @@ -143,7 +143,6 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, // evaluates if current frame is in directTouchMode (will if so be used next frame) if (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()) { // needs better definition? - //_vel.pan = glm::dvec2(0.0, 0.0); _directTouchMode = true; } else { @@ -250,18 +249,14 @@ void TouchInteraction::directControl(const std::vector& list) { // Gradient of distToMinimize w.r.t par (using forward difference) auto gradient = [](double* g, double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); + double h, der, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); glm::dvec3 camPos = ptr->camera->positionVec3(); - glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); - double h = 1e-11 * glm::distance(camPos, selectedPoint), hZoom = 1e-4; - double der, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); - double planetScale = ptr->node->boundingSphere() / 1e7; - if (planetScale > 1.0) { - hZoom *= planetScale; - h *= (planetScale / std::pow(10, fmod(planetScale,10.0) / 2.0)); - } + glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); + double hAngle = (1e-2 / ptr->node->boundingSphere()) / std::min(ptr->objectScreenRadius, 1000.0); + double hZoom = 1e-2 / std::min(ptr->objectScreenRadius, 300.0); for (int i = 0; i < ptr->nDOF; ++i) { - h = (i == 2) ? hZoom : h; // the 'zoom'-DOF is so big a smaller step creates NAN + h = (i == 2) ? hZoom : hAngle; // the 'zoom'-DOF is so big a smaller step creates NAN par[i] += h; f1 = ptr->distToMinimize(par, x, fdata, lmstat); par[i] -= h; @@ -277,11 +272,10 @@ void TouchInteraction::directControl(const std::vector& list) { else if (ptr->nDOF == 6) { for (int i = 0; i < ptr->nDOF; ++i) { // 3 finger case if (ptr->onlyPan) { // temp for feedback - g[i] = g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan + g[i] = (i == 2) ? g[i] : g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan } else { // do nothing - fits fingers well, but is difficult to control - //g[i] = (i < 4) ? g[i] : g[i] / std::abs(g[i]); // like it used to be, mute roll or not? } } } @@ -299,7 +293,18 @@ void TouchInteraction::directControl(const std::vector& list) { const int nFingers = list.size(); int nDOF = std::min(nFingers * 2, 6); - std::vector par(nDOF, 0.0); + std::vector par(nDOF, 0.0); // use _lastVel + par.at(0) = _lastVel.orbit.x; + par.at(1) = _lastVel.orbit.y; + if (nDOF > 2) { + par.at(2) = _lastVel.zoom; + par.at(3) = _lastVel.roll; + if (nDOF > 4) { + par.at(4) = _lastVel.pan.x; + par.at(5) = _lastVel.pan.y; + } + } + std::vector selectedPoints; std::vector screenPoints; for (const SelectedBody& sb : _selected) { @@ -309,11 +314,25 @@ void TouchInteraction::directControl(const std::vector& list) { screenPoints.push_back(glm::dvec2(2 * (c->getX() - 0.5), -2 * (c->getY() - 0.5))); // normalized -1 to 1 coordinates on screen } //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88, _lmstat, _onlyPan }; + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88, _lmstat, _onlyPan, _currentRadius }; void* dataPtr = reinterpret_cast(&fData); _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par + + glm::dvec3 camPos = _camera->positionVec3(); + glm::dvec3 selectedPoint = (node->rotationMatrix() * selectedPoints.at(0)) + node->worldPosition(); + //double hAngle = 5e-14 * glm::distance(camPos, selectedPoint); + //double hZoom = 1e-10 * node->boundingSphere() * log(glm::distance(camPos, selectedPoint)); + double hAngle = (1e-2 / node->boundingSphere()) / std::min(_currentRadius, 1000.0), hZoom = log(node->boundingSphere()) / std::min(_currentRadius, 300.0); + double h; + for (int i = 0; i < nDOF; ++i) { + h = (i == 2) ? hZoom : hAngle; + std::cout << "par(" << i << "): " << par[i] << ", "; + std::cout << "h(" << i << "): " << h << ", dist: " << log(glm::distance(camPos, selectedPoint)) << "\n"; + } + std::cout << "Radius: " << _currentRadius << "\n"; // 0.1 - 20000 + if (_lmSuccess && !_unitTest) { // if good values were found set new camera state _vel.orbit = glm::dvec2(par.at(0), par.at(1)); if (nDOF > 2) { @@ -590,7 +609,7 @@ void TouchInteraction::step(double dt) { // if we have chosen a new focus node if (_slerpdT < _slerpTime) { - _slerpdT += dt; + _slerpdT += 0.1*dt; localCamRot = slerp(localCamRot, _toSlerp, _slerpdT / _slerpTime); } } @@ -723,6 +742,10 @@ void TouchInteraction::resetAfterInput() { OnScreenGUIModule::touchInput.action = 0; } } + _lastVel.orbit = glm::dvec2(0.0, 0.0); + _lastVel.zoom = 0.0; + _lastVel.roll = 0.0; + _lastVel.pan = glm::dvec2(0.0, 0.0); _selected.clear(); // should clear if no longer have a direct-touch input } @@ -738,9 +761,9 @@ void TouchInteraction::resetToDefault() { _rollAngleThreshold.set(0.019f); _orbitSpeedThreshold.set(0.038f); _panSpeedThreshold.set(0.004f); - _spinSensitivity.set(0.25f); + _spinSensitivity.set(1.0f); _inputStillThreshold.set(0.0005f); - _interpretPan.set(0.01f); + _interpretPan.set(0.015f); _slerpTime.set(1.0f); _guiButton.set(glm::ivec2(32, 64)); _friction.set(glm::vec4(0.01, 0.02, 0.02, 0.02)); From 1eeb01d22d7314e7b2d73bf9a41fb10ec49f2750 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 24 May 2017 16:03:51 -0600 Subject: [PATCH 117/192] use an iterative method to find a good step size to take in gradient --- modules/touch/src/TouchInteraction.cpp | 63 ++++++++++++++------------ 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 46bb6494dc..05c2f4c0f9 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -249,20 +249,41 @@ void TouchInteraction::directControl(const std::vector& list) { // Gradient of distToMinimize w.r.t par (using forward difference) auto gradient = [](double* g, double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); - double h, der, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); - glm::dvec3 camPos = ptr->camera->positionVec3(); - glm::dvec3 selectedPoint = (ptr->node->rotationMatrix() * ptr->selectedPoints.at(x)) + ptr->node->worldPosition(); - double hAngle = (1e-2 / ptr->node->boundingSphere()) / std::min(ptr->objectScreenRadius, 1000.0); + double h, scale = log10(ptr->node->boundingSphere()), lastG, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); + double hAngle = (1e-2 / ptr->node->boundingSphere()) / std::min(ptr->objectScreenRadius, 300.0); double hZoom = 1e-2 / std::min(ptr->objectScreenRadius, 300.0); + std::vector dPar(ptr->nDOF, 0.0); for (int i = 0; i < ptr->nDOF; ++i) { - h = (i == 2) ? hZoom : hAngle; // the 'zoom'-DOF is so big a smaller step creates NAN + /*h = (i == 2) ? hZoom : hAngle; // the 'zoom'-DOF is so big a smaller step creates NAN par[i] += h; f1 = ptr->distToMinimize(par, x, fdata, lmstat); - par[i] -= h; - der = (f1 - f0) / h; - - g[i] = der; + par[i] -= h;*/ + + dPar.assign(par, par + ptr->nDOF); + h = 1e-8; + lastG = 1; + dPar.at(i) += h; + f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); + for (int j = 0; j < 100; ++j) { // iterative process to find the minimum step h that gives a good gradient + dPar.assign(par, par + ptr->nDOF); // reset parameters for precision + if ((f1 - f0) != 0 && lastG == 0) { // found good step size h + h *= scale * scale; + dPar.at(i) += h; + f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); + break; + } + else if ((f1 - f0) != 0 && lastG != 0) { // h too big + h /= scale; + } + else if ((f1 - f0) == 0) { // h too small + h *= scale; + } + lastG = f1 - f0; + dPar.at(i) += h; + f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); + } + g[i] = (f1 - f0) / h; } if (ptr->nDOF == 2) { for (int i = 0; i < 2; ++i) { @@ -319,19 +340,15 @@ void TouchInteraction::directControl(const std::vector& list) { _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - - glm::dvec3 camPos = _camera->positionVec3(); - glm::dvec3 selectedPoint = (node->rotationMatrix() * selectedPoints.at(0)) + node->worldPosition(); - //double hAngle = 5e-14 * glm::distance(camPos, selectedPoint); - //double hZoom = 1e-10 * node->boundingSphere() * log(glm::distance(camPos, selectedPoint)); - double hAngle = (1e-2 / node->boundingSphere()) / std::min(_currentRadius, 1000.0), hZoom = log(node->boundingSphere()) / std::min(_currentRadius, 300.0); + // debug + /*double hAngle = (1e-2 / node->boundingSphere()) / std::min(_currentRadius, 1000.0), hZoom = log(node->boundingSphere()) / std::min(_currentRadius, 300.0); double h; for (int i = 0; i < nDOF; ++i) { h = (i == 2) ? hZoom : hAngle; - std::cout << "par(" << i << "): " << par[i] << ", "; - std::cout << "h(" << i << "): " << h << ", dist: " << log(glm::distance(camPos, selectedPoint)) << "\n"; + std::cout << "par(" << i << "): " << par[i] << ", " << "h(" << i << "): " << h << "\n"; } - std::cout << "Radius: " << _currentRadius << "\n"; // 0.1 - 20000 + std::cout << "Radius: " << _currentRadius << "\n";*/ + //std::cout << "Levmarq success after " << _lmstat.final_it << " iterations\n"; if (_lmSuccess && !_unitTest) { // if good values were found set new camera state _vel.orbit = glm::dvec2(par.at(0), par.at(1)); @@ -352,16 +369,6 @@ void TouchInteraction::directControl(const std::vector& list) { _vel.roll = 0.0; _vel.pan = glm::dvec2(0.0, 0.0); } - - // debugging - if (_lmstat.verbose) { - /*std::cout << _lmstat.data; - std::ostringstream os; - for (int i = 0; i < nDOF; ++i) { - os << par[i] << ", "; - } - std::cout << "Levmarq success after " << _lmstat.final_it << " iterations. Values: " << os.str() << "\n";*/ - } } // Traces the touch input into the scene and finds the surface coordinates of touched planets (if occuring) From c3e1f54b457255517f0c3b79cc72acabcac15b0a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 24 May 2017 16:25:16 -0600 Subject: [PATCH 118/192] stubb for TouchMarker class to render where the contact points are on the screen --- modules/touch/CMakeLists.txt | 2 ++ modules/touch/include/TouchMarker.h | 55 +++++++++++++++++++++++++++++ modules/touch/include/TuioEar.h | 1 - modules/touch/src/TouchMarker.cpp | 44 +++++++++++++++++++++++ modules/touch/touchmodule.cpp | 6 ++++ modules/touch/touchmodule.h | 1 + 6 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 modules/touch/include/TouchMarker.h create mode 100644 modules/touch/src/TouchMarker.cpp diff --git a/modules/touch/CMakeLists.txt b/modules/touch/CMakeLists.txt index 48f12b0afb..0538960a92 100644 --- a/modules/touch/CMakeLists.txt +++ b/modules/touch/CMakeLists.txt @@ -28,6 +28,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.h ${CMAKE_CURRENT_SOURCE_DIR}/include/TuioEar.h ${CMAKE_CURRENT_SOURCE_DIR}/include/TouchInteraction.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/TouchMarker.h ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -35,6 +36,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TuioEar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TouchInteraction.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/TouchMarker.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h new file mode 100644 index 0000000000..b582c870de --- /dev/null +++ b/modules/touch/include/TouchMarker.h @@ -0,0 +1,55 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_TOUCH___MARKER___H__ +#define __OPENSPACE_TOUCH___MARKER___H__ + + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + + +namespace openspace { + +class TouchMarker : public properties::PropertyOwner +{ + public: + TouchMarker(); + + private: + +}; + +} // openspace namespace + +#endif // __OPENSPACE_TOUCH___MARKER___H__ diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index ef90fb3056..7312f883dd 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -36,7 +36,6 @@ #include #include #include -#include #include diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp new file mode 100644 index 0000000000..71281b0972 --- /dev/null +++ b/modules/touch/src/TouchMarker.cpp @@ -0,0 +1,44 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace { + const std::string _loggerCat = "TouchMarker"; +} +namespace openspace { + +TouchMarker::TouchMarker() + : properties::PropertyOwner("TouchMarker") { } + +} // openspace namespace \ No newline at end of file diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index d5613b9994..92f8306cf7 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -125,6 +125,12 @@ TouchModule::TouchModule() touch.step(OsEng.windowWrapper().deltaTime()); } ); + + OsEng.registerModuleCallback( + OpenSpaceEngine::CallbackOption::PostDraw, + []() { + } + ); } } // namespace openspace diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 4cae20213c..3eb38e1593 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace openspace { From 8c5e33be1300b1bfd5c9573a003f85eebec99b29 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 25 May 2017 16:50:32 -0600 Subject: [PATCH 119/192] refinement on gradient step size and fix to 'freeze' issue --- modules/touch/include/TouchInteraction.h | 1 + modules/touch/src/TouchInteraction.cpp | 24 +++++++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 1f0aee5b9f..0ec155f929 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -138,6 +138,7 @@ class TouchInteraction : public properties::PropertyOwner double _slerpdT; double _timeSlack; int _numOfTests; + int _numOfTries; TUIO::TuioTime _time; bool _directTouchMode; bool _tap; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 05c2f4c0f9..89a43d53ac 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -82,7 +82,7 @@ TouchInteraction::TouchInteraction() _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) }, _centroid{ glm::dvec3(0.0) }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack { 0.0 }, + _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _numOfTries{ 0 }, _timeSlack{ 0.0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { addProperty(_touchActive); // how do i hide this? @@ -268,7 +268,7 @@ void TouchInteraction::directControl(const std::vector& list) { for (int j = 0; j < 100; ++j) { // iterative process to find the minimum step h that gives a good gradient dPar.assign(par, par + ptr->nDOF); // reset parameters for precision if ((f1 - f0) != 0 && lastG == 0) { // found good step size h - h *= scale * scale; + h *= std::max(scale * scale, 10.0); dPar.at(i) += h; f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); break; @@ -351,6 +351,7 @@ void TouchInteraction::directControl(const std::vector& list) { //std::cout << "Levmarq success after " << _lmstat.final_it << " iterations\n"; if (_lmSuccess && !_unitTest) { // if good values were found set new camera state + _numOfTries = 0; _vel.orbit = glm::dvec2(par.at(0), par.at(1)); if (nDOF > 2) { _vel.zoom = par.at(2); @@ -369,6 +370,12 @@ void TouchInteraction::directControl(const std::vector& list) { _vel.roll = 0.0; _vel.pan = glm::dvec2(0.0, 0.0); } + else { + _numOfTries++; + if (_numOfTries > 3) { + resetAfterInput(); + } + } } // Traces the touch input into the scene and finds the surface coordinates of touched planets (if occuring) @@ -726,10 +733,8 @@ void TouchInteraction::decelerate(double dt) { // Called if all fingers are off the screen void TouchInteraction::resetAfterInput() { //ghoul_postcondition(_selected.empty(), "Selected list must be empty after reset"); - _lmSuccess = true; - _guiON = OnScreenGUIModule::gui.isEnabled(); //_directTouchMode = false; - if (_directTouchMode && _selected.size() > 0) { + if (_directTouchMode && _selected.size() > 0 && _lmSuccess) { double spinDelta = _spinSensitivity / OsEng.windowWrapper().averageDeltaTime(); if (glm::length(_lastVel.pan) > _panSpeedThreshold) { // might not be desired _vel.pan = _lastVel.pan * spinDelta; @@ -749,6 +754,15 @@ void TouchInteraction::resetAfterInput() { OnScreenGUIModule::touchInput.action = 0; } } + else { + OnScreenGUIModule::touchInput.active = false; + OnScreenGUIModule::touchInput.action = 0; + } + + _lmSuccess = true; + _numOfTries = 0; + _guiON = OnScreenGUIModule::gui.isEnabled(); + _lastVel.orbit = glm::dvec2(0.0, 0.0); _lastVel.zoom = 0.0; _lastVel.roll = 0.0; From 776d688899b74f56cc77a64d6d12e2962bbd3af6 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 30 May 2017 16:55:01 -0600 Subject: [PATCH 120/192] improved performance by choosing step size more intelligently in gradient of LMA --- modules/touch/src/TouchInteraction.cpp | 34 +++++++++++++++----------- openspace.cfg | 4 +-- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 89a43d53ac..5af1a95c07 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -249,9 +249,8 @@ void TouchInteraction::directControl(const std::vector& list) { // Gradient of distToMinimize w.r.t par (using forward difference) auto gradient = [](double* g, double* par, int x, void* fdata, LMstat* lmstat) { FunctionData* ptr = reinterpret_cast(fdata); - double h, scale = log10(ptr->node->boundingSphere()), lastG, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); - double hAngle = (1e-2 / ptr->node->boundingSphere()) / std::min(ptr->objectScreenRadius, 300.0); - double hZoom = 1e-2 / std::min(ptr->objectScreenRadius, 300.0); + double h, hZoom, lastG, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); + double scale = log10(ptr->node->boundingSphere()); // scale value to find minimum step size h, dependant on planet size std::vector dPar(ptr->nDOF, 0.0); for (int i = 0; i < ptr->nDOF; ++i) { @@ -259,16 +258,26 @@ void TouchInteraction::directControl(const std::vector& list) { par[i] += h; f1 = ptr->distToMinimize(par, x, fdata, lmstat); par[i] -= h;*/ - dPar.assign(par, par + ptr->nDOF); h = 1e-8; lastG = 1; dPar.at(i) += h; f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); for (int j = 0; j < 100; ++j) { // iterative process to find the minimum step h that gives a good gradient - dPar.assign(par, par + ptr->nDOF); // reset parameters for precision - if ((f1 - f0) != 0 && lastG == 0) { // found good step size h - h *= std::max(scale * scale, 10.0); + dPar.assign(par, par + ptr->nDOF); + if ((f1 - f0) != 0 && lastG == 0) { // found minimum step size h + // scale up to get a good initial guess value + h *= scale * scale * scale; + + // find optimal h + if (i == 2) { + h = std::max(std::min(std::abs(dPar.at(i)) / 1e8, 1.0), h); // choose zoom step size dependant on incoming zoom parameter + } + else if (ptr->nDOF == 2) { + h = std::max(std::abs(dPar.at(i)) * 0.001, h); // make sure the angle step size isnt smaller than a fraction of the incoming parameter for 1 finger + } + + // calculate f1 with good h for finite difference dPar.at(i) += h; f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); break; @@ -285,13 +294,13 @@ void TouchInteraction::directControl(const std::vector& list) { } g[i] = (f1 - f0) / h; } - if (ptr->nDOF == 2) { + if (ptr->nDOF == 2) { // normalize on 1 finger case to allow for horizontal/vertical movement for (int i = 0; i < 2; ++i) { g[i] = g[i]/std::abs(g[i]); } } else if (ptr->nDOF == 6) { - for (int i = 0; i < ptr->nDOF; ++i) { // 3 finger case + for (int i = 0; i < ptr->nDOF; ++i) { // lock to only pan and zoom on 3 finger case if (ptr->onlyPan) { // temp for feedback g[i] = (i == 2) ? g[i] : g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan } @@ -372,7 +381,7 @@ void TouchInteraction::directControl(const std::vector& list) { } else { _numOfTries++; - if (_numOfTries > 3) { + if (_numOfTries > 2) { resetAfterInput(); } } @@ -744,10 +753,7 @@ void TouchInteraction::resetAfterInput() { } } if (_guiON) { - bool activeLastFrame = false; - if (OnScreenGUIModule::touchInput.action) { - activeLastFrame = true; - } + bool activeLastFrame = OnScreenGUIModule::touchInput.action; OnScreenGUIModule::touchInput.active = false; if (activeLastFrame) { OnScreenGUIModule::touchInput.active = true; diff --git a/openspace.cfg b/openspace.cfg index 2f5d727c33..cca4d91e1b 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,12 +7,12 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, + --SGCTConfig = sgct.config.single{}, -- SGCTConfig = sgct.config.single{res={1920, 1080}, shared=true}, -- A regular 1920x1080 window - --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From de75f783ba77ae0102e891e90961ed8e3d0111b5 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 1 Jun 2017 16:56:26 -0600 Subject: [PATCH 121/192] using projectionMatrix instead of hardcoded projection, seems to have affected the gradient step size h (much larger now) --- modules/touch/include/TouchInteraction.h | 6 +- modules/touch/src/TouchInteraction.cpp | 137 +++++++++++------------ 2 files changed, 70 insertions(+), 73 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 0ec155f929..95559bfb1c 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -72,11 +72,10 @@ class TouchInteraction : public properties::PropertyOwner std::vector selectedPoints; std::vector screenPoints; int nDOF; - glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*, double); + glm::dvec2(*castToNDC)(glm::dvec3, Camera&, SceneGraphNode*); double(*distToMinimize)(double* par, int x, void* fdata, LMstat* lmstat); Camera* camera; SceneGraphNode* node; - double aspectRatio; LMstat stats; bool onlyPan; // temp double objectScreenRadius; @@ -97,7 +96,7 @@ class TouchInteraction : public properties::PropertyOwner private: bool guiMode(const std::vector& list); - void directControl(const std::vector& list); + void directControl(const std::vector& list, const std::vector& lastProcessed); void findSelectedNode(const std::vector& list); int interpretInteraction(const std::vector& list, const std::vector& lastProcessed); void computeVelocities(const std::vector& list, const std::vector& lastProcessed); @@ -138,7 +137,6 @@ class TouchInteraction : public properties::PropertyOwner double _slerpdT; double _timeSlack; int _numOfTests; - int _numOfTries; TUIO::TuioTime _time; bool _directTouchMode; bool _tap; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 5af1a95c07..3c7927e0cd 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -56,11 +56,11 @@ namespace { using namespace TUIO; namespace openspace { -TouchInteraction::TouchInteraction() - : properties::PropertyOwner("TouchInteraction"), - _origin("origin", "Origin", ""), - _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), - _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", true), // temp + TouchInteraction::TouchInteraction() + : properties::PropertyOwner("TouchInteraction"), + _origin("origin", "Origin", ""), + _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), + _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", false), // temp _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), _reset("Default Values", "Reset all properties to default", false), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), @@ -68,7 +68,7 @@ TouchInteraction::TouchInteraction() _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.1, 0.0, 0.5), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), - _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.019f, 0.0f, 0.05f), + _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.025f, 0.0f, 0.05f), _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.005f, 0.0f, 0.01f), _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.0005f, 0.0, 0.01), _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 1.0f, 0, 2), @@ -82,7 +82,7 @@ TouchInteraction::TouchInteraction() _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) }, _centroid{ glm::dvec3(0.0) }, _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _numOfTries{ 0 }, _timeSlack{ 0.0 }, + _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack{ 0.0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { addProperty(_touchActive); // how do i hide this? @@ -132,7 +132,7 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, if (!guiMode(list)) { if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { - directControl(list); + directControl(list, lastProcessed); } if (_lmSuccess) { findSelectedNode(list); @@ -151,6 +151,7 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, } } +// Activates/Deactivates gui input mode (if active it voids all other interactions) bool TouchInteraction::guiMode(const std::vector& list) { WindowWrapper& wrapper = OsEng.windowWrapper(); glm::ivec2 res = wrapper.currentWindowSize(); @@ -171,7 +172,7 @@ bool TouchInteraction::guiMode(const std::vector& list) { } // Sets _vel to update _camera according to direct-manipulation (L2 error) -void TouchInteraction::directControl(const std::vector& list) { +void TouchInteraction::directControl(const std::vector& list, const std::vector& lastProcessed) { // Reset old velocities upon new interaction _vel.orbit = glm::dvec2(0.0, 0.0); _vel.zoom = 0.0; @@ -207,13 +208,13 @@ void TouchInteraction::directControl(const std::vector& list) { dquat localCamRot = inverse(globalCamRot) * ptr->camera->rotationQuaternion(); { // Roll - dquat camRollRot = angleAxis(q[3], dvec3(0.0, 0.0, 1.0)); - localCamRot = localCamRot * camRollRot; + dquat rollRot = angleAxis(q[3], dvec3(0.0, 0.0, 1.0)); + localCamRot = localCamRot * rollRot; } { // Panning (local rotation) dvec3 eulerAngles(q[5], q[4], 0); - dquat rotationDiff = dquat(eulerAngles); - localCamRot = localCamRot * rotationDiff; + dquat panRot = dquat(eulerAngles); + localCamRot = localCamRot * panRot; } { // Orbit (global rotation) dvec3 eulerAngles(q[1], q[0], 0); @@ -235,14 +236,13 @@ void TouchInteraction::directControl(const std::vector& list) { { // Zooming camPos += directionToCenter * q[2]; } - // Update the camera state Camera cam = *(ptr->camera); cam.setPositionVec3(camPos); cam.setRotation(globalCamRot * localCamRot); // we now have a new position and orientation of camera, project surfacePoint to the new screen to get distance to minimize - glm::dvec2 newScreenPoint = ptr->castToNDC(ptr->selectedPoints.at(x), cam, ptr->node, ptr->aspectRatio); + glm::dvec2 newScreenPoint = ptr->castToNDC(ptr->selectedPoints.at(x), cam, ptr->node); lmstat->pos.push_back(newScreenPoint); return glm::length(ptr->screenPoints.at(x) - newScreenPoint); }; @@ -252,34 +252,49 @@ void TouchInteraction::directControl(const std::vector& list) { double h, hZoom, lastG, f1, f0 = ptr->distToMinimize(par, x, fdata, lmstat); double scale = log10(ptr->node->boundingSphere()); // scale value to find minimum step size h, dependant on planet size std::vector dPar(ptr->nDOF, 0.0); + dPar.assign(par, par + ptr->nDOF); + /* + Paper: + p = h(Vx) + * p = position in screen space + * x = position in world space + * V = projection * worldToCam + * h = redefine to 2D = [x/w,y/w] + Mine: + p = h * projection * worldToCam * x + worldToCam contains the parameter q + + h'(x) = [1/w, 0 + 0, 1/w + 0, 0 + -x/w2, -y/w2] + J = h'(projection * worldToCam * x) * d(Vx)/d(q) + p = Jq - linear function of q even though its nonlinear + */ for (int i = 0; i < ptr->nDOF; ++i) { - /*h = (i == 2) ? hZoom : hAngle; // the 'zoom'-DOF is so big a smaller step creates NAN - par[i] += h; - f1 = ptr->distToMinimize(par, x, fdata, lmstat); - par[i] -= h;*/ - dPar.assign(par, par + ptr->nDOF); h = 1e-8; lastG = 1; dPar.at(i) += h; f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); + dPar.at(i) = par[i]; for (int j = 0; j < 100; ++j) { // iterative process to find the minimum step h that gives a good gradient - dPar.assign(par, par + ptr->nDOF); if ((f1 - f0) != 0 && lastG == 0) { // found minimum step size h // scale up to get a good initial guess value h *= scale * scale * scale; - + // find optimal h if (i == 2) { - h = std::max(std::min(std::abs(dPar.at(i)) / 1e8, 1.0), h); // choose zoom step size dependant on incoming zoom parameter + h = std::max(std::abs(dPar.at(i)) / 1e4, h); // choose zoom step size dependant on incoming zoom parameter } else if (ptr->nDOF == 2) { - h = std::max(std::abs(dPar.at(i)) * 0.001, h); // make sure the angle step size isnt smaller than a fraction of the incoming parameter for 1 finger + h = std::max(std::abs(dPar.at(i)) * 0.01, h); // make sure the angle step size isnt smaller than a fraction of the incoming parameter for 1 finger } // calculate f1 with good h for finite difference dPar.at(i) += h; f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); + dPar.at(i) = par[i]; break; } else if ((f1 - f0) != 0 && lastG != 0) { // h too big @@ -291,8 +306,10 @@ void TouchInteraction::directControl(const std::vector& list) { lastG = f1 - f0; dPar.at(i) += h; f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); + dPar.at(i) = par[i]; } g[i] = (f1 - f0) / h; + //std::cout << "h(" << i << "): " << h << ", g(" << i << "): " << g[i] << "\n"; } if (ptr->nDOF == 2) { // normalize on 1 finger case to allow for horizontal/vertical movement for (int i = 0; i < 2; ++i) { @@ -301,33 +318,35 @@ void TouchInteraction::directControl(const std::vector& list) { } else if (ptr->nDOF == 6) { for (int i = 0; i < ptr->nDOF; ++i) { // lock to only pan and zoom on 3 finger case - if (ptr->onlyPan) { // temp for feedback - g[i] = (i == 2) ? g[i] : g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan - } - else { - // do nothing - fits fingers well, but is difficult to control - } + g[i] = (i == 2) ? g[i] : g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan } } }; - SceneGraphNode* node = _selected.at(0).node; - auto castToNDC = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node, double aspectRatio) { - glm::dvec3 backToScreenSpace = glm::inverse(camera.rotationQuaternion()) - * glm::normalize(((node->rotationMatrix() * vec) + (node->worldPosition() - camera.positionVec3()) )); - backToScreenSpace *= (-3.2596558 / backToScreenSpace.z); - backToScreenSpace.x /= aspectRatio; + auto castToNDC = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node) { + glm::dvec3 posInCamSpace = glm::inverse(camera.rotationQuaternion()) + * ((node->rotationMatrix() * vec) + (node->worldPosition() - camera.positionVec3()) ); - return glm::dvec2(backToScreenSpace); + glm::dvec4 clipspace = camera.projectionMatrix() * glm::dvec4(posInCamSpace, 1.0); + return (glm::dvec2(clipspace) / clipspace.w); }; const int nFingers = list.size(); int nDOF = std::min(nFingers * 2, 6); - std::vector par(nDOF, 0.0); // use _lastVel + std::vector par(nDOF, 0.0); // use _lastVel, + + // check if zoom direction has changed + /*double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { + return d + c.getDistance(_centroid.x, _centroid.y); + }) / list.size(); + double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { + return d + p.second.getDistance(_centroid.x, _centroid.y); + }) / lastProcessed.size();*/ + par.at(0) = _lastVel.orbit.x; par.at(1) = _lastVel.orbit.y; if (nDOF > 2) { - par.at(2) = _lastVel.zoom; + par.at(2) = _lastVel.zoom; //((distance < lastDistance && _lastVel.zoom < 0.0) || (distance > lastDistance && _lastVel.zoom > 0.0)) ? _lastVel.zoom : -_lastVel.zoom; par.at(3) = _lastVel.roll; if (nDOF > 4) { par.at(4) = _lastVel.pan.x; @@ -343,24 +362,15 @@ void TouchInteraction::directControl(const std::vector& list) { std::vector::const_iterator c = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return c.getSessionID() == sb.id; }); screenPoints.push_back(glm::dvec2(2 * (c->getX() - 0.5), -2 * (c->getY() - 0.5))); // normalized -1 to 1 coordinates on screen } - //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, node, 1.88, _lmstat, _onlyPan, _currentRadius }; + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, _selected.at(0).node, _lmstat, _onlyPan, _currentRadius }; void* dataPtr = reinterpret_cast(&fData); _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par // debug - /*double hAngle = (1e-2 / node->boundingSphere()) / std::min(_currentRadius, 1000.0), hZoom = log(node->boundingSphere()) / std::min(_currentRadius, 300.0); - double h; - for (int i = 0; i < nDOF; ++i) { - h = (i == 2) ? hZoom : hAngle; - std::cout << "par(" << i << "): " << par[i] << ", " << "h(" << i << "): " << h << "\n"; - } - std::cout << "Radius: " << _currentRadius << "\n";*/ //std::cout << "Levmarq success after " << _lmstat.final_it << " iterations\n"; if (_lmSuccess && !_unitTest) { // if good values were found set new camera state - _numOfTries = 0; _vel.orbit = glm::dvec2(par.at(0), par.at(1)); if (nDOF > 2) { _vel.zoom = par.at(2); @@ -379,12 +389,6 @@ void TouchInteraction::directControl(const std::vector& list) { _vel.roll = 0.0; _vel.pan = glm::dvec2(0.0, 0.0); } - else { - _numOfTries++; - if (_numOfTries > 2) { - resetAfterInput(); - } - } } // Traces the touch input into the scene and finds the surface coordinates of touched planets (if occuring) @@ -400,19 +404,16 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { if (node->name() == name) selectableNodes.push_back(node); - //glm::dvec2 res = OsEng.windowWrapper().currentWindowResolution(); - // @COMMENT ^_^ - double aspectRatio = 1.88; //res.x/res.y; glm::dquat camToWorldSpace = _camera->rotationQuaternion(); glm::dvec3 camPos = _camera->positionVec3(); std::vector newSelected; for (const TuioCursor& c : list) { - double xCo = 2 * (c.getX() - 0.5) * aspectRatio; + double xCo = 2 * (c.getX() - 0.5); double yCo = -2 * (c.getY() - 0.5); // normalized -1 to 1 coordinates on screen - glm::dvec3 cursorInWorldSpace = camToWorldSpace * glm::dvec3(xCo, yCo, -3.2596558); + glm::dvec3 cursorInWorldSpace = camToWorldSpace * + glm::dvec3(glm::inverse(_camera->projectionMatrix()) * glm::dvec4(xCo, yCo, -1.0, 1.0)); // vec3(projectionmatrix * clipspace), divide with w? glm::dvec3 raytrace = glm::normalize(cursorInWorldSpace); - int id = c.getSessionID(); for (SceneGraphNode* node : selectableNodes) { double boundingSphere = node->boundingSphere(); @@ -446,10 +447,9 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { _selected = newSelected; //debugging - for (auto it : newSelected) { - //std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << - //", Node at:" << glm::to_string(it.node->worldPosition()) << ", Camera at: " << glm::to_string(_camera->positionVec3()) << "\n"; - } + /*for (auto it : newSelected) { + std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; + }*/ } // Interprets the input gesture to a specific interaction @@ -702,7 +702,7 @@ void TouchInteraction::unitTest() { // call update findSelectedNode(lastFrame); - directControl(currFrame); + //directControl(currFrame); // save lmstats.data into a file and clear it char buffer[32]; @@ -766,7 +766,6 @@ void TouchInteraction::resetAfterInput() { } _lmSuccess = true; - _numOfTries = 0; _guiON = OnScreenGUIModule::gui.isEnabled(); _lastVel.orbit = glm::dvec2(0.0, 0.0); @@ -778,14 +777,14 @@ void TouchInteraction::resetAfterInput() { void TouchInteraction::resetToDefault() { _unitTest.set(false); - _onlyPan.set(true); // temp + _onlyPan.set(false); // temp _reset.set(false); _maxTapTime.set(300); _deceleratesPerSecond.set(240); _touchScreenSize.set(55.0f); _tapZoomFactor.set(0.1f); _nodeRadiusThreshold.set(0.2f); - _rollAngleThreshold.set(0.019f); + _rollAngleThreshold.set(0.025f); _orbitSpeedThreshold.set(0.038f); _panSpeedThreshold.set(0.004f); _spinSensitivity.set(1.0f); From d0492b25162cd72a43bdafd6aa577c555d6bec27 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 6 Jun 2017 14:17:53 -0600 Subject: [PATCH 122/192] fix misinterpretation on roll, fixed step size in LMA gradient the projectionmatrix caused, fixed infinite spin bug on LMA failure --- modules/touch/include/TouchInteraction.h | 3 +- modules/touch/src/TouchInteraction.cpp | 86 +++++++++--------------- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 95559bfb1c..066fbeaac1 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -96,7 +96,7 @@ class TouchInteraction : public properties::PropertyOwner private: bool guiMode(const std::vector& list); - void directControl(const std::vector& list, const std::vector& lastProcessed); + void directControl(const std::vector& list); void findSelectedNode(const std::vector& list); int interpretInteraction(const std::vector& list, const std::vector& lastProcessed); void computeVelocities(const std::vector& list, const std::vector& lastProcessed); @@ -122,6 +122,7 @@ class TouchInteraction : public properties::PropertyOwner properties::FloatProperty _panSpeedThreshold; properties::FloatProperty _spinSensitivity; properties::FloatProperty _inputStillThreshold; + properties::FloatProperty _centroidStillThreshold; properties::FloatProperty _interpretPan; properties::FloatProperty _slerpTime; properties::IVec2Property _guiButton; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 3c7927e0cd..f36b8c3ba7 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -56,11 +56,11 @@ namespace { using namespace TUIO; namespace openspace { - TouchInteraction::TouchInteraction() - : properties::PropertyOwner("TouchInteraction"), - _origin("origin", "Origin", ""), - _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), - _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", false), // temp +TouchInteraction::TouchInteraction() + : properties::PropertyOwner("TouchInteraction"), + _origin("origin", "Origin", ""), + _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), + _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", false), // temp _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), _reset("Default Values", "Reset all properties to default", false), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), @@ -73,10 +73,11 @@ namespace openspace { _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.0005f, 0.0, 0.01), _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 1.0f, 0, 2), _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0005f, 0, 0.001), + _centroidStillThreshold("Centroid stationary", "Threshold for stationary centroid", 0.0018f, 0, 0.01), // used to void wrongly interpreted roll interactions _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.015f, 0, 0.1), _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 1, 0, 5), _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), - _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.02, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), + _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.025, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) }, _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) }, @@ -100,6 +101,7 @@ namespace openspace { addProperty(_panSpeedThreshold); addProperty(_spinSensitivity); addProperty(_inputStillThreshold); + addProperty(_centroidStillThreshold); addProperty(_interpretPan); addProperty(_slerpTime); addProperty(_guiButton); @@ -132,7 +134,7 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, if (!guiMode(list)) { if (_directTouchMode && _selected.size() > 0 && list.size() == _selected.size()) { - directControl(list, lastProcessed); + directControl(list); } if (_lmSuccess) { findSelectedNode(list); @@ -172,7 +174,7 @@ bool TouchInteraction::guiMode(const std::vector& list) { } // Sets _vel to update _camera according to direct-manipulation (L2 error) -void TouchInteraction::directControl(const std::vector& list, const std::vector& lastProcessed) { +void TouchInteraction::directControl(const std::vector& list) { // Reset old velocities upon new interaction _vel.orbit = glm::dvec2(0.0, 0.0); _vel.zoom = 0.0; @@ -253,25 +255,7 @@ void TouchInteraction::directControl(const std::vector& list, const double scale = log10(ptr->node->boundingSphere()); // scale value to find minimum step size h, dependant on planet size std::vector dPar(ptr->nDOF, 0.0); dPar.assign(par, par + ptr->nDOF); - /* - Paper: - p = h(Vx) - * p = position in screen space - * x = position in world space - * V = projection * worldToCam - * h = redefine to 2D = [x/w,y/w] - Mine: - p = h * projection * worldToCam * x - worldToCam contains the parameter q - - h'(x) = [1/w, 0 - 0, 1/w - 0, 0 - -x/w2, -y/w2] - J = h'(projection * worldToCam * x) * d(Vx)/d(q) - p = Jq - linear function of q even though its nonlinear - */ for (int i = 0; i < ptr->nDOF; ++i) { h = 1e-8; lastG = 1; @@ -283,12 +267,13 @@ void TouchInteraction::directControl(const std::vector& list, const // scale up to get a good initial guess value h *= scale * scale * scale; - // find optimal h + // clamp max step size to a fraction of the incoming parameter if (i == 2) { - h = std::max(std::abs(dPar.at(i)) / 1e4, h); // choose zoom step size dependant on incoming zoom parameter + double epsilon = 1e-4; + h = std::max(std::max(std::abs(dPar.at(i)), epsilon) * 0.01, h); // make sure incoming parameter is larger than 0 } else if (ptr->nDOF == 2) { - h = std::max(std::abs(dPar.at(i)) * 0.01, h); // make sure the angle step size isnt smaller than a fraction of the incoming parameter for 1 finger + h = std::max(std::abs(dPar.at(i)) * 0.001, h); } // calculate f1 with good h for finite difference @@ -309,7 +294,6 @@ void TouchInteraction::directControl(const std::vector& list, const dPar.at(i) = par[i]; } g[i] = (f1 - f0) / h; - //std::cout << "h(" << i << "): " << h << ", g(" << i << "): " << g[i] << "\n"; } if (ptr->nDOF == 2) { // normalize on 1 finger case to allow for horizontal/vertical movement for (int i = 0; i < 2; ++i) { @@ -318,11 +302,12 @@ void TouchInteraction::directControl(const std::vector& list, const } else if (ptr->nDOF == 6) { for (int i = 0; i < ptr->nDOF; ++i) { // lock to only pan and zoom on 3 finger case - g[i] = (i == 2) ? g[i] : g[i] / std::abs(g[i]); // no zoom, weird roll sometimes, otherwise only pan + g[i] = (i == 2) ? g[i] : g[i] / std::abs(g[i]); } } }; + // project back a 3D point in model view to clip space [-1,1] coordinates on the view plane auto castToNDC = [](glm::dvec3 vec, Camera& camera, SceneGraphNode* node) { glm::dvec3 posInCamSpace = glm::inverse(camera.rotationQuaternion()) * ((node->rotationMatrix() * vec) + (node->worldPosition() - camera.positionVec3()) ); @@ -333,26 +318,9 @@ void TouchInteraction::directControl(const std::vector& list, const const int nFingers = list.size(); int nDOF = std::min(nFingers * 2, 6); - std::vector par(nDOF, 0.0); // use _lastVel, - - // check if zoom direction has changed - /*double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { - return d + c.getDistance(_centroid.x, _centroid.y); - }) / list.size(); - double lastDistance = std::accumulate(lastProcessed.begin(), lastProcessed.end(), 0.0f, [&](float d, const Point& p) { - return d + p.second.getDistance(_centroid.x, _centroid.y); - }) / lastProcessed.size();*/ - - par.at(0) = _lastVel.orbit.x; + std::vector par(nDOF, 0.0); + par.at(0) = _lastVel.orbit.x; // use _lastVel for orbit par.at(1) = _lastVel.orbit.y; - if (nDOF > 2) { - par.at(2) = _lastVel.zoom; //((distance < lastDistance && _lastVel.zoom < 0.0) || (distance > lastDistance && _lastVel.zoom > 0.0)) ? _lastVel.zoom : -_lastVel.zoom; - par.at(3) = _lastVel.roll; - if (nDOF > 4) { - par.at(4) = _lastVel.pan.x; - par.at(5) = _lastVel.pan.y; - } - } std::vector selectedPoints; std::vector screenPoints; @@ -366,8 +334,6 @@ void TouchInteraction::directControl(const std::vector& list, const void* dataPtr = reinterpret_cast(&fData); _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - - // debug //std::cout << "Levmarq success after " << _lmstat.final_it << " iterations\n"; if (_lmSuccess && !_unitTest) { // if good values were found set new camera state @@ -389,6 +355,9 @@ void TouchInteraction::directControl(const std::vector& list, const _vel.roll = 0.0; _vel.pan = glm::dvec2(0.0, 0.0); } + else { // prevents touch to infinitely be active (due to windows bridge case where event doesnt get consumed) + OnScreenGUIModule::touchInput = { 1, glm::dvec2(0.0, 0.0), 1 }; + } } // Traces the touch input into the scene and finds the surface coordinates of touched planets (if occuring) @@ -448,13 +417,16 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { //debugging /*for (auto it : newSelected) { - std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) << "\n"; + std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) + << "\n"; }*/ } // Interprets the input gesture to a specific interaction int TouchInteraction::interpretInteraction(const std::vector& list, const std::vector& lastProcessed) { //ghoul_precondition(!list.empty(), "List must not be empty"); + + glm::dvec3 lastCentroid = _centroid; _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); @@ -514,7 +486,8 @@ int TouchInteraction::interpretInteraction(const std::vector& list, if (std::abs(dist - lastDist) / list.at(0).getMotionSpeed() < _interpretPan && list.size() == 3) { // if distance between fingers is constant we have panning return PAN; } - else if (std::abs(minDiff) < _inputStillThreshold || std::abs(rollOn) < 100.0) { // if one finger is 'still' (epsilon) and another moving, we have roll + // we have roll if one finger is still, or the total roll angles around the centroid is over _rollAngleThreshold (_centroidStillThreshold is used to void misinterpretations) + else if (std::abs(minDiff) < _inputStillThreshold || (std::abs(rollOn) < 100.0 && glm::distance(_centroid, lastCentroid) / list.size() < _centroidStillThreshold)) { return ROLL; // also interpret if angles are high } else { @@ -702,7 +675,7 @@ void TouchInteraction::unitTest() { // call update findSelectedNode(lastFrame); - //directControl(currFrame); + directControl(currFrame); // save lmstats.data into a file and clear it char buffer[32]; @@ -789,10 +762,11 @@ void TouchInteraction::resetToDefault() { _panSpeedThreshold.set(0.004f); _spinSensitivity.set(1.0f); _inputStillThreshold.set(0.0005f); + _centroidStillThreshold.set(0.0018f); _interpretPan.set(0.015f); _slerpTime.set(1.0f); _guiButton.set(glm::ivec2(32, 64)); - _friction.set(glm::vec4(0.01, 0.02, 0.02, 0.02)); + _friction.set(glm::vec4(0.01, 0.025, 0.02, 0.02)); } void TouchInteraction::tap() { From 58c6f17acfde6699e9b1f4e4dc93d55a8c6aa931 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 7 Jun 2017 11:45:55 -0600 Subject: [PATCH 123/192] fix to duplicate refs --- openspace.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openspace.cfg b/openspace.cfg index cca4d91e1b..2f5d727c33 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,12 +7,12 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - --SGCTConfig = sgct.config.single{}, + SGCTConfig = sgct.config.single{}, -- SGCTConfig = sgct.config.single{res={1920, 1080}, shared=true}, -- A regular 1920x1080 window - SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From d3f574ba235fbe6583dfe4671a8511047a775997 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 9 Jun 2017 15:24:36 -0600 Subject: [PATCH 124/192] render TouchMarkers, currently causes crash on runtime --- modules/touch/CMakeLists.txt | 12 ++- modules/touch/include/TouchMarker.h | 47 +++++++-- modules/touch/shaders/marker_fs.glsl | 66 ++++++++++++ modules/touch/shaders/marker_vs.glsl | 43 ++++++++ modules/touch/src/TouchMarker.cpp | 147 +++++++++++++++++++++++++-- modules/touch/src/TuioEar.cpp | 1 - modules/touch/touchmodule.cpp | 22 +++- modules/touch/touchmodule.h | 5 +- 8 files changed, 323 insertions(+), 20 deletions(-) create mode 100644 modules/touch/shaders/marker_fs.glsl create mode 100644 modules/touch/shaders/marker_vs.glsl diff --git a/modules/touch/CMakeLists.txt b/modules/touch/CMakeLists.txt index 0538960a92..bceb2918a8 100644 --- a/modules/touch/CMakeLists.txt +++ b/modules/touch/CMakeLists.txt @@ -25,7 +25,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.h + ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.h ${CMAKE_CURRENT_SOURCE_DIR}/include/TuioEar.h ${CMAKE_CURRENT_SOURCE_DIR}/include/TouchInteraction.h ${CMAKE_CURRENT_SOURCE_DIR}/include/TouchMarker.h @@ -33,17 +33,23 @@ set(HEADER_FILES source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ext/levmarq.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TuioEar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TouchInteraction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/TouchMarker.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) + +set(SHADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/marker_fs.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/marker_vs.glsl +) +source_group("Shader Files" FILES ${SHADER_FILES}) create_new_module( "Touch" touch_module - ${HEADER_FILES} ${SOURCE_FILES} + ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) include_external_library(${touch_module} libTUIO ${CMAKE_CURRENT_SOURCE_DIR}/ext/libTUIO) \ No newline at end of file diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h index b582c870de..533512969b 100644 --- a/modules/touch/include/TouchMarker.h +++ b/modules/touch/include/TouchMarker.h @@ -25,29 +25,64 @@ #ifndef __OPENSPACE_TOUCH___MARKER___H__ #define __OPENSPACE_TOUCH___MARKER___H__ +#include +#include +#include #include #include +#include #include +#include + #include - -#include +#include #include -#include -#include -#include +namespace ghoul { +namespace opengl { + class ProgramObject; + class Texture; +} // namespace opengl +} // namespace ghoul namespace openspace { +struct RenderData; +struct UpdateData; + class TouchMarker : public properties::PropertyOwner { public: TouchMarker(); - private: + bool initialize(const std::vector list); + bool deinitialize(); + bool isReady() const; + + void render(const std::vector list); + void update(); + + + private: + void loadTexture(); + void createVertexList(const std::vector list); + + properties::StringProperty _texturePath; + properties::BoolProperty _visible; + properties::FloatProperty _radiusSize; + + std::unique_ptr _shader; + std::unique_ptr _texture; + + GLuint _quad; + GLuint _vertexPositionBuffer; + int _numFingers; + + bool _listIsDirty; + bool _textureIsDirty; }; } // openspace namespace diff --git a/modules/touch/shaders/marker_fs.glsl b/modules/touch/shaders/marker_fs.glsl new file mode 100644 index 0000000000..5921c7262a --- /dev/null +++ b/modules/touch/shaders/marker_fs.glsl @@ -0,0 +1,66 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +in vec2 out_position; +in float pointRadius; + +out vec4 FragColor; + +void main () { + + // calculate normal from texture coordinates + //vec3 n; + //n.xy = gl_PointCoord.st*vec2(2.0, -2.0) + vec2(-1.0, 1.0); + //float mag = dot(n.xy, n.xy); + //if (mag > 1.0) discard; // kill pixels outside circle + //n.z = sqrt(1.0-mag); + + //vec3 eye = mvPosition + vec3(0.0, 0.0, pointRadius * n.z); + //float depth = (P[2][2] * eye.z + P[3][2]) / (P[2][3] * eye.z + P[3][3]); + + //gl_FragDepth = (depth + 1.0) / 2.0; + + + // calculate lighting + //const vec3 light_dir = vec3(0.0, 0.0, 1.0); + //float diffuse = max(0.0, dot(light_dir, n)); + + //vec3 halfVector = normalize( eye + light_dir); + //float spec = pow(max(0.0, dot(n,halfVector)), 100.0); + + // modify color according to the velocity + //vec3 color = vec3(0.3, 0.3, 0.9); + //vec3 hsv = rgb2hsv(color); + //float v = length(outVelocity); + //v = min((1.0/maxVelocity)*v*v, 1.0); + //vec3 fluidColor = hsv2rgb(vec3(hsv.x, max(1.0 - v, 0.0), 1.0)); + + // compute final color + //vec3 outColor = 0.25 * fluidColor; + //outColor += 0.7 * diffuse * fluidColor; + //outColor += 0.05 * spec * vec3(1.0); + //outColor = clamp(outColor, 0.0, 1.0); + + FragColor = vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/modules/touch/shaders/marker_vs.glsl b/modules/touch/shaders/marker_vs.glsl new file mode 100644 index 0000000000..ccd7e0e94a --- /dev/null +++ b/modules/touch/shaders/marker_vs.glsl @@ -0,0 +1,43 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +// Vertex attributes +layout(location = 0) in vec2 in_position; + +// Uniforms +uniform float radius; + +// Outputs +out vec2 out_position; +out float pointRadius; + +void main() { + out_position = in_position; + pointRadius = 0.05; //radius; + + gl_PointSize = 0.05; //radius; + gl_Position = in_position; +} \ No newline at end of file diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index 71281b0972..ce9a5ecf29 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -25,11 +25,12 @@ #include #include -#include -#include -#include #include -#include +#include +#include +#include +#include +#include #include @@ -38,7 +39,141 @@ namespace { } namespace openspace { -TouchMarker::TouchMarker() - : properties::PropertyOwner("TouchMarker") { } +TouchMarker::TouchMarker() + : properties::PropertyOwner("TouchMarker") + , _visible("TouchMarkers visible", "Toggle visibility of markers", false) + , _radiusSize("Marker size", "Set marker size in radius", 0.5, 0, 1) + , _texturePath("texturePath", "Color Texture") + , _shader(nullptr) + , _texture(nullptr) + , _listIsDirty(false) + , _textureIsDirty(false) + , _numFingers(0) +{ + addProperty(_visible); + addProperty(_radiusSize); + addProperty(_texturePath); + _texturePath.onChange(std::bind(&TouchMarker::loadTexture, this)); + + +} + +bool TouchMarker::isReady() const { + if (_shader == nullptr) { + std::cout << "something went wrong\n"; + } + return (_shader != nullptr); // && _texture; +} + +bool TouchMarker::initialize(const std::vector list) { + glGenVertexArrays(1, &_quad); // generate array + glGenBuffers(1, &_vertexPositionBuffer); // generate buffer + createVertexList(list); + + _shader = OsEng.renderEngine().buildRenderProgram("MarkerProgram", + "${MODULE_TOUCH}/shaders/marker_vs.glsl", + "${MODULE_TOUCH}/shaders/marker_fs.glsl" + ); + + //loadTexture(); + + return isReady(); +} + +bool TouchMarker::deinitialize() { + glDeleteVertexArrays(1, &_quad); + _quad = 0; + + glDeleteBuffers(1, &_vertexPositionBuffer); + _vertexPositionBuffer = 0; + + _texture = nullptr; + + RenderEngine& renderEngine = OsEng.renderEngine(); + if (_shader) { + renderEngine.removeRenderProgram(_shader); + _shader = nullptr; + } + + return true; +} + +void TouchMarker::render(const std::vector list) { + if (_visible) { + createVertexList(list); + _shader->activate(); + + // Bind texture + /*ghoul::opengl::TextureUnit unit; + unit.activate(); + _texture->bind(); + _shader->setUniform("texture1", unit);*/ + _shader->setUniform("radius", _radiusSize); + + glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + glBindVertexArray(_quad); + glDrawArrays(GL_POINTS, 0, _numFingers); + + _shader->deactivate(); + } +} + +void TouchMarker::update() { + if (_shader->isDirty()) + _shader->rebuildFromFile(); + + if (_listIsDirty) + //createFingerList(); + + if (_textureIsDirty) { + loadTexture(); + _textureIsDirty = false; + } +} + +void TouchMarker::loadTexture() { + if (_texturePath.value() != "") { + std::unique_ptr texture = + ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath)); + + if (texture) { + LDEBUGC( + "TouchMarker", + "Loaded texture from '" << absPath(_texturePath) << "'" + ); + texture->uploadTexture(); + + // Textures of planets looks much smoother with AnisotropicMipMap rather than linear + texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + + _texture = std::move(texture); + } + } +} + +void TouchMarker::createVertexList(const std::vector list) { + _numFingers = list.size(); + std::vector vertexData(_numFingers * 2, 0); + int i = 0; + for (const TUIO::TuioCursor& c : list) { + vertexData.at(i) = 2 * (c.getX() - 0.5); + vertexData.at(i + 1) = -2 * (c.getY() - 0.5); + i += 2; + } + + glBindVertexArray(_quad); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData.data()), vertexData.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 2, + GL_FLOAT, + GL_FALSE, + 0, + reinterpret_cast(0) + ); +} } // openspace namespace \ No newline at end of file diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 10f652441e..adab44040f 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -23,7 +23,6 @@ ****************************************************************************************/ #include -#include #include #include diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 92f8306cf7..4e58ef4e1d 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -102,7 +102,24 @@ TouchModule::TouchModule() : OpenSpaceModule("Touch") { addPropertySubOwner(touch); - + addPropertySubOwner(markers); + + OsEng.registerModuleCallback( + OpenSpaceEngine::CallbackOption::InitializeGL, + [&]() { + LDEBUGC("TouchModule", "Initializing TouchMarker OpenGL"); + markers.initialize(listOfContactPoints); + } + ); + + OsEng.registerModuleCallback( + OpenSpaceEngine::CallbackOption::DeinitializeGL, + [&]() { + LDEBUGC("TouchMarker", "Deinitialize TouchMarker OpenGL"); + markers.deinitialize(); + } + ); + OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::PreSync, [&]() { @@ -128,7 +145,8 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::PostDraw, - []() { + [&]() { + markers.render(listOfContactPoints); } ); } diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 3eb38e1593..1bcd88b49f 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -26,9 +26,9 @@ #define __OPENSPACE_MODULE_TOUCH___TOUCHMODULE___H__ #include -#include -#include #include +#include + namespace openspace { @@ -42,6 +42,7 @@ namespace openspace { TuioEar ear; TouchInteraction touch; + TouchMarker markers; std::vector listOfContactPoints; std::vector lastProcessed; // contains an id and the TuioPoint that was processed last frame }; From 23f524d141afec5919b81e19426b8f039f112497 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 9 Jun 2017 15:43:35 -0600 Subject: [PATCH 125/192] cleanup and shader compile fix --- modules/touch/include/TouchMarker.h | 4 ---- modules/touch/shaders/marker_fs.glsl | 2 +- modules/touch/shaders/marker_vs.glsl | 8 ++++---- modules/touch/src/TouchMarker.cpp | 11 ++--------- 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h index 533512969b..6f5e84359b 100644 --- a/modules/touch/include/TouchMarker.h +++ b/modules/touch/include/TouchMarker.h @@ -49,8 +49,6 @@ namespace opengl { namespace openspace { -struct RenderData; -struct UpdateData; class TouchMarker : public properties::PropertyOwner { @@ -60,8 +58,6 @@ class TouchMarker : public properties::PropertyOwner bool initialize(const std::vector list); bool deinitialize(); - bool isReady() const; - void render(const std::vector list); void update(); diff --git a/modules/touch/shaders/marker_fs.glsl b/modules/touch/shaders/marker_fs.glsl index 5921c7262a..7bf99e2f06 100644 --- a/modules/touch/shaders/marker_fs.glsl +++ b/modules/touch/shaders/marker_fs.glsl @@ -23,7 +23,7 @@ ****************************************************************************************/ in vec2 out_position; -in float pointRadius; +//in float pointRadius; out vec4 FragColor; diff --git a/modules/touch/shaders/marker_vs.glsl b/modules/touch/shaders/marker_vs.glsl index ccd7e0e94a..1cc46c4802 100644 --- a/modules/touch/shaders/marker_vs.glsl +++ b/modules/touch/shaders/marker_vs.glsl @@ -28,16 +28,16 @@ layout(location = 0) in vec2 in_position; // Uniforms -uniform float radius; +//uniform float radius; // Outputs out vec2 out_position; -out float pointRadius; +//out float pointRadius; void main() { out_position = in_position; - pointRadius = 0.05; //radius; + //pointRadius = 0.05; //radius; gl_PointSize = 0.05; //radius; - gl_Position = in_position; + gl_Position = vec3(in_position, -1.0, 1.0); } \ No newline at end of file diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index ce9a5ecf29..b80c9c149d 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -58,13 +58,6 @@ TouchMarker::TouchMarker() } -bool TouchMarker::isReady() const { - if (_shader == nullptr) { - std::cout << "something went wrong\n"; - } - return (_shader != nullptr); // && _texture; -} - bool TouchMarker::initialize(const std::vector list) { glGenVertexArrays(1, &_quad); // generate array glGenBuffers(1, &_vertexPositionBuffer); // generate buffer @@ -77,7 +70,7 @@ bool TouchMarker::initialize(const std::vector list) { //loadTexture(); - return isReady(); + return (_shader != nullptr); // && _texture; } bool TouchMarker::deinitialize() { @@ -108,7 +101,7 @@ void TouchMarker::render(const std::vector list) { unit.activate(); _texture->bind(); _shader->setUniform("texture1", unit);*/ - _shader->setUniform("radius", _radiusSize); + //_shader->setUniform("radius", _radiusSize); glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); From 5ef64aa513cb97c82cb8caaa1ab031c889032db5 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 9 Jun 2017 17:48:07 -0600 Subject: [PATCH 126/192] gl_position is vec4, cleanup/tests --- modules/touch/include/TouchMarker.h | 1 - modules/touch/shaders/marker_vs.glsl | 2 +- modules/touch/src/TouchMarker.cpp | 8 ++------ 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h index 6f5e84359b..cd7d21a456 100644 --- a/modules/touch/include/TouchMarker.h +++ b/modules/touch/include/TouchMarker.h @@ -77,7 +77,6 @@ class TouchMarker : public properties::PropertyOwner GLuint _vertexPositionBuffer; int _numFingers; - bool _listIsDirty; bool _textureIsDirty; }; diff --git a/modules/touch/shaders/marker_vs.glsl b/modules/touch/shaders/marker_vs.glsl index 1cc46c4802..9109a41988 100644 --- a/modules/touch/shaders/marker_vs.glsl +++ b/modules/touch/shaders/marker_vs.glsl @@ -39,5 +39,5 @@ void main() { //pointRadius = 0.05; //radius; gl_PointSize = 0.05; //radius; - gl_Position = vec3(in_position, -1.0, 1.0); + gl_Position = vec4(in_position, -1.0, 1.0); } \ No newline at end of file diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index b80c9c149d..9bb7781bbe 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -46,7 +46,6 @@ TouchMarker::TouchMarker() , _texturePath("texturePath", "Color Texture") , _shader(nullptr) , _texture(nullptr) - , _listIsDirty(false) , _textureIsDirty(false) , _numFingers(0) { @@ -116,9 +115,6 @@ void TouchMarker::update() { if (_shader->isDirty()) _shader->rebuildFromFile(); - if (_listIsDirty) - //createFingerList(); - if (_textureIsDirty) { loadTexture(); _textureIsDirty = false; @@ -147,7 +143,7 @@ void TouchMarker::loadTexture() { void TouchMarker::createVertexList(const std::vector list) { _numFingers = list.size(); - std::vector vertexData(_numFingers * 2, 0); + std::vector vertexData(_numFingers * 2, 0.0f); int i = 0; for (const TUIO::TuioCursor& c : list) { vertexData.at(i) = 2 * (c.getX() - 0.5); @@ -164,7 +160,7 @@ void TouchMarker::createVertexList(const std::vector list) { 2, GL_FLOAT, GL_FALSE, - 0, + sizeof(GLfloat) * 2, reinterpret_cast(0) ); } From c53bcaac05595e1e18276853caf4461c13e44549 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 13 Jun 2017 13:54:43 -0600 Subject: [PATCH 127/192] markers working, alpha and textures are not --- modules/touch/include/TouchMarker.h | 2 +- modules/touch/shaders/marker_fs.glsl | 40 ++++++++++------------ modules/touch/shaders/marker_vs.glsl | 5 ++- modules/touch/src/TouchMarker.cpp | 51 ++++++++++++++-------------- modules/touch/touchmodule.cpp | 2 +- 5 files changed, 47 insertions(+), 53 deletions(-) diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h index cd7d21a456..3cead1533f 100644 --- a/modules/touch/include/TouchMarker.h +++ b/modules/touch/include/TouchMarker.h @@ -55,7 +55,7 @@ class TouchMarker : public properties::PropertyOwner public: TouchMarker(); - bool initialize(const std::vector list); + bool initialize(); bool deinitialize(); void render(const std::vector list); diff --git a/modules/touch/shaders/marker_fs.glsl b/modules/touch/shaders/marker_fs.glsl index 7bf99e2f06..e15318779a 100644 --- a/modules/touch/shaders/marker_fs.glsl +++ b/modules/touch/shaders/marker_fs.glsl @@ -23,22 +23,23 @@ ****************************************************************************************/ in vec2 out_position; -//in float pointRadius; -out vec4 FragColor; +uniform float radius; -void main () { +#include "PowerScaling/powerScaling_fs.hglsl" +#include "fragment.glsl" + +Fragment getFragment() { // calculate normal from texture coordinates - //vec3 n; - //n.xy = gl_PointCoord.st*vec2(2.0, -2.0) + vec2(-1.0, 1.0); - //float mag = dot(n.xy, n.xy); - //if (mag > 1.0) discard; // kill pixels outside circle - //n.z = sqrt(1.0-mag); + vec3 n; + n.xy = gl_PointCoord.st*vec2(2.0, -2.0) + vec2(-1.0, 1.0); + float mag = dot(n.xy, n.xy); + if (mag > 1.0) discard; // kill pixels outside circle + n.z = sqrt(1.0-mag); - //vec3 eye = mvPosition + vec3(0.0, 0.0, pointRadius * n.z); + //vec3 eye = vec3(0.0, 0.0, radius * n.z); //float depth = (P[2][2] * eye.z + P[3][2]) / (P[2][3] * eye.z + P[3][3]); - //gl_FragDepth = (depth + 1.0) / 2.0; @@ -49,18 +50,11 @@ void main () { //vec3 halfVector = normalize( eye + light_dir); //float spec = pow(max(0.0, dot(n,halfVector)), 100.0); - // modify color according to the velocity - //vec3 color = vec3(0.3, 0.3, 0.9); - //vec3 hsv = rgb2hsv(color); - //float v = length(outVelocity); - //v = min((1.0/maxVelocity)*v*v, 1.0); - //vec3 fluidColor = hsv2rgb(vec3(hsv.x, max(1.0 - v, 0.0), 1.0)); + vec3 color = vec3(1.0, 1.0, 1.0); + float alpha = mag; - // compute final color - //vec3 outColor = 0.25 * fluidColor; - //outColor += 0.7 * diffuse * fluidColor; - //outColor += 0.05 * spec * vec3(1.0); - //outColor = clamp(outColor, 0.0, 1.0); - - FragColor = vec4(1.0, 1.0, 1.0, 1.0); + Fragment frag; + frag.color = vec4(color, alpha); + frag.depth = 1.0; + return frag; } \ No newline at end of file diff --git a/modules/touch/shaders/marker_vs.glsl b/modules/touch/shaders/marker_vs.glsl index 9109a41988..b8eef6a91f 100644 --- a/modules/touch/shaders/marker_vs.glsl +++ b/modules/touch/shaders/marker_vs.glsl @@ -28,7 +28,7 @@ layout(location = 0) in vec2 in_position; // Uniforms -//uniform float radius; +uniform float radius; // Outputs out vec2 out_position; @@ -36,8 +36,7 @@ out vec2 out_position; void main() { out_position = in_position; - //pointRadius = 0.05; //radius; - gl_PointSize = 0.05; //radius; + gl_PointSize = radius; gl_Position = vec4(in_position, -1.0, 1.0); } \ No newline at end of file diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index 9bb7781bbe..2876b09e5b 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -36,13 +36,14 @@ namespace { const std::string _loggerCat = "TouchMarker"; + const int MAX_FINGERS = 20; } namespace openspace { TouchMarker::TouchMarker() : properties::PropertyOwner("TouchMarker") - , _visible("TouchMarkers visible", "Toggle visibility of markers", false) - , _radiusSize("Marker size", "Set marker size in radius", 0.5, 0, 1) + , _visible("TouchMarkers visible", "Toggle visibility of markers", true) + , _radiusSize("Marker size", "Set marker size in radius", 10, 0, 30) , _texturePath("texturePath", "Color Texture") , _shader(nullptr) , _texture(nullptr) @@ -57,15 +58,19 @@ TouchMarker::TouchMarker() } -bool TouchMarker::initialize(const std::vector list) { +bool TouchMarker::initialize() { glGenVertexArrays(1, &_quad); // generate array glGenBuffers(1, &_vertexPositionBuffer); // generate buffer - createVertexList(list); - _shader = OsEng.renderEngine().buildRenderProgram("MarkerProgram", - "${MODULE_TOUCH}/shaders/marker_vs.glsl", - "${MODULE_TOUCH}/shaders/marker_fs.glsl" - ); + try { + _shader = OsEng.renderEngine().buildRenderProgram("MarkerProgram", + "${MODULE_TOUCH}/shaders/marker_vs.glsl", + "${MODULE_TOUCH}/shaders/marker_fs.glsl" + ); + } + catch (const ghoul::opengl::ShaderObject::ShaderCompileError& e) { + LERRORC(e.component, e.what()); + } //loadTexture(); @@ -91,7 +96,7 @@ bool TouchMarker::deinitialize() { } void TouchMarker::render(const std::vector list) { - if (_visible) { + if (_visible && !list.empty()) { createVertexList(list); _shader->activate(); @@ -100,7 +105,7 @@ void TouchMarker::render(const std::vector list) { unit.activate(); _texture->bind(); _shader->setUniform("texture1", unit);*/ - //_shader->setUniform("radius", _radiusSize); + _shader->setUniform("radius", _radiusSize); glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); @@ -123,45 +128,41 @@ void TouchMarker::update() { void TouchMarker::loadTexture() { if (_texturePath.value() != "") { - std::unique_ptr texture = - ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath)); + _texture = ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath)); - if (texture) { + if (_texture) { LDEBUGC( "TouchMarker", "Loaded texture from '" << absPath(_texturePath) << "'" ); - texture->uploadTexture(); - - // Textures of planets looks much smoother with AnisotropicMipMap rather than linear - texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - - _texture = std::move(texture); + _texture->uploadTexture(); + _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); // linear or mipmap? } } } void TouchMarker::createVertexList(const std::vector list) { _numFingers = list.size(); - std::vector vertexData(_numFingers * 2, 0.0f); + std::vector vertexData(_numFingers * 2, 0); + GLfloat vertexTest[MAX_FINGERS]; int i = 0; for (const TUIO::TuioCursor& c : list) { - vertexData.at(i) = 2 * (c.getX() - 0.5); - vertexData.at(i + 1) = -2 * (c.getY() - 0.5); + vertexTest[i] = 2 * (c.getX() - 0.5); + vertexTest[i + 1] = -2 * (c.getY() - 0.5); i += 2; } glBindVertexArray(_quad); glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData.data()), vertexData.data(), GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertexTest), vertexTest, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, - sizeof(GLfloat) * 2, - reinterpret_cast(0) + 0, + 0 ); } diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 4e58ef4e1d..ab1826948e 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -108,7 +108,7 @@ TouchModule::TouchModule() OpenSpaceEngine::CallbackOption::InitializeGL, [&]() { LDEBUGC("TouchModule", "Initializing TouchMarker OpenGL"); - markers.initialize(listOfContactPoints); + markers.initialize(); } ); From b1be00a0ebbf8adfc3fb90b2ba51e9b515746d8a Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 14 Jun 2017 14:09:54 -0600 Subject: [PATCH 128/192] added transparency, thickness and color control to the markers --- modules/touch/include/TouchMarker.h | 4 +++ modules/touch/shaders/marker_fs.glsl | 21 ++++++---------- modules/touch/src/TouchMarker.cpp | 37 ++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h index 3cead1533f..d17313a9f9 100644 --- a/modules/touch/include/TouchMarker.h +++ b/modules/touch/include/TouchMarker.h @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -69,6 +70,9 @@ class TouchMarker : public properties::PropertyOwner properties::StringProperty _texturePath; properties::BoolProperty _visible; properties::FloatProperty _radiusSize; + properties::FloatProperty _transparency; + properties::FloatProperty _thickness; + properties::Vec3Property _color; std::unique_ptr _shader; std::unique_ptr _texture; diff --git a/modules/touch/shaders/marker_fs.glsl b/modules/touch/shaders/marker_fs.glsl index e15318779a..5e10ff3bdd 100644 --- a/modules/touch/shaders/marker_fs.glsl +++ b/modules/touch/shaders/marker_fs.glsl @@ -25,6 +25,9 @@ in vec2 out_position; uniform float radius; +uniform float transparency; +uniform float thickness; +uniform vec3 color; #include "PowerScaling/powerScaling_fs.hglsl" #include "fragment.glsl" @@ -37,24 +40,14 @@ Fragment getFragment() { float mag = dot(n.xy, n.xy); if (mag > 1.0) discard; // kill pixels outside circle n.z = sqrt(1.0-mag); - - //vec3 eye = vec3(0.0, 0.0, radius * n.z); - //float depth = (P[2][2] * eye.z + P[3][2]) / (P[2][3] * eye.z + P[3][3]); - //gl_FragDepth = (depth + 1.0) / 2.0; - // calculate lighting - //const vec3 light_dir = vec3(0.0, 0.0, 1.0); - //float diffuse = max(0.0, dot(light_dir, n)); - - //vec3 halfVector = normalize( eye + light_dir); - //float spec = pow(max(0.0, dot(n,halfVector)), 100.0); - - vec3 color = vec3(1.0, 1.0, 1.0); - float alpha = mag; + const vec3 light_dir = vec3(0.0, 0.0, 1.0); + float diffuse = max(0.0, dot(light_dir, n)); + float alpha = min(pow(mag, thickness), transparency); Fragment frag; - frag.color = vec4(color, alpha); + frag.color = vec4(color * diffuse, alpha); frag.depth = 1.0; return frag; } \ No newline at end of file diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index 2876b09e5b..3d98c8db12 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -43,7 +43,16 @@ namespace openspace { TouchMarker::TouchMarker() : properties::PropertyOwner("TouchMarker") , _visible("TouchMarkers visible", "Toggle visibility of markers", true) - , _radiusSize("Marker size", "Set marker size in radius", 10, 0, 30) + , _radiusSize("Marker size", "Marker radius", 30, 0, 50) + , _transparency("Transparency of marker", "Marker transparency", 0.8, 0, 1.0) + , _thickness("Thickness of marker", "Marker thickness", 1.0, 0, 2.0) + , _color( + "MarkerColor", + "Marker color", + glm::vec3(204.f / 255.f, 51.f / 255.f, 51.f / 255.f), + glm::vec3(0.f), + glm::vec3(1.f) + ) , _texturePath("texturePath", "Color Texture") , _shader(nullptr) , _texture(nullptr) @@ -52,9 +61,13 @@ TouchMarker::TouchMarker() { addProperty(_visible); addProperty(_radiusSize); + addProperty(_transparency); + addProperty(_thickness); + _color.setViewOption(properties::Property::ViewOptions::Color); + addProperty(_color); addProperty(_texturePath); _texturePath.onChange(std::bind(&TouchMarker::loadTexture, this)); - + //_texturePath.set("?"); } @@ -106,8 +119,17 @@ void TouchMarker::render(const std::vector list) { _texture->bind(); _shader->setUniform("texture1", unit);*/ _shader->setUniform("radius", _radiusSize); - + _shader->setUniform("transparency", _transparency); + _shader->setUniform("thickness", _thickness); + _shader->setUniform("color", _color.value()); + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_SCISSOR_TEST); glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); glBindVertexArray(_quad); glDrawArrays(GL_POINTS, 0, _numFingers); @@ -143,18 +165,17 @@ void TouchMarker::loadTexture() { void TouchMarker::createVertexList(const std::vector list) { _numFingers = list.size(); - std::vector vertexData(_numFingers * 2, 0); - GLfloat vertexTest[MAX_FINGERS]; + GLfloat vertexData[MAX_FINGERS]; int i = 0; for (const TUIO::TuioCursor& c : list) { - vertexTest[i] = 2 * (c.getX() - 0.5); - vertexTest[i + 1] = -2 * (c.getY() - 0.5); + vertexData[i] = 2 * (c.getX() - 0.5); + vertexData[i + 1] = -2 * (c.getY() - 0.5); i += 2; } glBindVertexArray(_quad); glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertexTest), vertexTest, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer( 0, From ad142580c297372472ba5beb550a61348c946936 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 16 Jun 2017 17:57:08 -0600 Subject: [PATCH 129/192] cleanup --- modules/touch/shaders/marker_fs.glsl | 2 +- modules/touch/src/TouchInteraction.cpp | 6 +++--- modules/touch/src/TouchMarker.cpp | 7 ++----- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/touch/shaders/marker_fs.glsl b/modules/touch/shaders/marker_fs.glsl index 5e10ff3bdd..ba814149e0 100644 --- a/modules/touch/shaders/marker_fs.glsl +++ b/modules/touch/shaders/marker_fs.glsl @@ -44,7 +44,7 @@ Fragment getFragment() { // calculate lighting const vec3 light_dir = vec3(0.0, 0.0, 1.0); float diffuse = max(0.0, dot(light_dir, n)); - float alpha = min(pow(mag, thickness), transparency); + float alpha = min(pow(sqrt(mag), thickness), transparency); Fragment frag; frag.color = vec4(color * diffuse, alpha); diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index f36b8c3ba7..ccf78a52fd 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -64,7 +64,7 @@ TouchInteraction::TouchInteraction() _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), _reset("Default Values", "Reset all properties to default", false), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), - _deceleratesPerSecond("Decelerates per second", "Deceleration rate of velocity, times per second", 240, 60, 300), + _deceleratesPerSecond("Decelerates per second", "Number of times velocity is decelerated per second", 240, 60, 300), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.1, 0.0, 0.5), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), @@ -758,8 +758,8 @@ void TouchInteraction::resetToDefault() { _tapZoomFactor.set(0.1f); _nodeRadiusThreshold.set(0.2f); _rollAngleThreshold.set(0.025f); - _orbitSpeedThreshold.set(0.038f); - _panSpeedThreshold.set(0.004f); + _orbitSpeedThreshold.set(0.005f); + _panSpeedThreshold.set(0.0005f); _spinSensitivity.set(1.0f); _inputStillThreshold.set(0.0005f); _centroidStillThreshold.set(0.0018f); diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index 3d98c8db12..6cbf67277f 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -43,9 +43,9 @@ namespace openspace { TouchMarker::TouchMarker() : properties::PropertyOwner("TouchMarker") , _visible("TouchMarkers visible", "Toggle visibility of markers", true) - , _radiusSize("Marker size", "Marker radius", 30, 0, 50) + , _radiusSize("Marker size", "Marker radius", 30, 0, 100) , _transparency("Transparency of marker", "Marker transparency", 0.8, 0, 1.0) - , _thickness("Thickness of marker", "Marker thickness", 1.0, 0, 2.0) + , _thickness("Thickness of marker", "Marker thickness", 1.0, 0, 4.0) , _color( "MarkerColor", "Marker color", @@ -126,10 +126,7 @@ void TouchMarker::render(const std::vector list) { glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_SCISSOR_TEST); glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); glBindVertexArray(_quad); glDrawArrays(GL_POINTS, 0, _numFingers); From 7f39ebb49cdcc05ce623bc6b656869764f699623 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Tue, 20 Jun 2017 15:06:38 -0600 Subject: [PATCH 130/192] cleanup and commented all code --- modules/touch/ext/levmarq.h | 9 ++ modules/touch/include/TouchInteraction.h | 55 ++++++++++- modules/touch/include/TouchMarker.h | 7 -- modules/touch/include/TuioEar.h | 24 ++++- modules/touch/src/TouchInteraction.cpp | 116 ++++++++++------------- modules/touch/src/TouchMarker.cpp | 47 +-------- modules/touch/src/TuioEar.cpp | 4 + modules/touch/touchmodule.cpp | 19 ++-- modules/touch/touchmodule.h | 3 + openspace.cfg | 4 +- 10 files changed, 153 insertions(+), 135 deletions(-) diff --git a/modules/touch/ext/levmarq.h b/modules/touch/ext/levmarq.h index d3c7d77892..c15f1c47ae 100644 --- a/modules/touch/ext/levmarq.h +++ b/modules/touch/ext/levmarq.h @@ -42,13 +42,22 @@ typedef struct { double final_derr; } LMstat; +/** +* Initialize parameters to good values +*/ void levmarq_init(LMstat *lmstat); +/** +* Main function call, finds appropriate values for par[nDOF] that manipulates the camera correctly to direct-manipulation +*/ bool levmarq(int npar, double *par, int ny, double *dysq, double (*func)(double *, int, void *, LMstat*), void (*grad)(double *, double *, int, void *, LMstat*), void *fdata, LMstat *lmstat); +/** +* Returns the total L2 error (to be minimized) with each contact point's distance from the projected coordinates depending on par[nDOF]. +*/ double error_func(double *par, int ny, double *dysq, double (*func)(double *, int, void *, LMstat*), void *fdata, LMstat* lmstat); diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 066fbeaac1..912bc0cfb4 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -44,8 +44,6 @@ #include #endif -#include - namespace openspace { class TouchInteraction : public properties::PropertyOwner @@ -55,19 +53,23 @@ class TouchInteraction : public properties::PropertyOwner public: TouchInteraction(); + // for interpretInteraction() enum Type { ROT = 0, PINCH, PAN, ROLL, PICK }; + // Stores the velocity in all 6DOF struct VelocityStates { glm::dvec2 orbit; double zoom; double roll; glm::dvec2 pan; }; + // Stores the selected node, the cursor ID as well as the surface coordinates the cursor touched struct SelectedBody { int id; SceneGraphNode* node; glm::dvec3 coordinates; }; + // Used in the LM algorithm struct FunctionData { std::vector selectedPoints; std::vector screenPoints; @@ -77,15 +79,37 @@ class TouchInteraction : public properties::PropertyOwner Camera* camera; SceneGraphNode* node; LMstat stats; - bool onlyPan; // temp double objectScreenRadius; }; + /* Main function call + * 1, Checks if doubleTap occured + * 2, Goes through the guiMode() function + * 3, Continues if GUI isn't on + * 4, If the node in focus is large enough and all contact points have selected it, + * calls directControl() function for direct-manipulation + * 5, Updates std::vector _selected (only if LMA successfully + * converged, avoids interaction to snap on LMA fails) + * 6, If directControl() wasn't called this frame, interpret the incoming + * list and decide what type of interaction this frame should do + * 7, Compute the new total velocities after interaction + * 8, Evaluate if directControl should be called next frame - true if all contact points + * select the same node and said node is larger than _nodeRadiusThreshold + */ void updateStateFromInput(const std::vector& list, std::vector& lastProcessed); + + /* Calculates the new camera state with velocities and time since last frame */ void step(double dt); + + /* Used to save LMA data for one frame if the user chose to */ void unitTest(); + + /* Called each frame we have no new input, used to reset data */ void resetAfterInput(); + + /* Sets _tap to true, called if tap occured current frame (called from touchmodule) */ void tap(); + /* Set touchactive as true from the touchmodule if incoming list isn't empty, used to void mouse input */ void touchActive(bool active); // Get & Setters @@ -95,12 +119,35 @@ class TouchInteraction : public properties::PropertyOwner void setCamera(Camera* cam); private: + + /* Returns true if we have the GUI window open + If so, emulates the incoming touch input to a mouse such that we can interact with the GUI + */ bool guiMode(const std::vector& list); + + /* Function that calculates the new camera state such that it minimizes the L2 error in screenspace + * between contact points and surface coordinates projected to clip space using LMA + */ void directControl(const std::vector& list); + + /* Traces each contact point into the scene as a ray + * if the ray hits a node, save the id, node and surface coordinates the cursor hit in the list _selected + */ void findSelectedNode(const std::vector& list); + + /* Returns an int (ROT = 0, PINCH, PAN, ROLL, PICK) for what interaction to be used, + depending on what input was gotten */ int interpretInteraction(const std::vector& list, const std::vector& lastProcessed); + + /* Compute new velocity according to the interpreted action */ void computeVelocities(const std::vector& list, const std::vector& lastProcessed); + + /* Decelerate the velocities, + * function is called in step() but is dereferenced from frame time to assure same behaviour on all systems + */ void decelerate(double dt); + + /* Resets all properties that can be changed in the GUI to default */ void resetToDefault(); Camera* _camera; @@ -109,7 +156,6 @@ class TouchInteraction : public properties::PropertyOwner // Property variables properties::StringProperty _origin; properties::BoolProperty _unitTest; - properties::BoolProperty _onlyPan; // temp properties::BoolProperty _touchActive; properties::BoolProperty _reset; properties::IntProperty _maxTapTime; @@ -119,7 +165,6 @@ class TouchInteraction : public properties::PropertyOwner properties::FloatProperty _nodeRadiusThreshold; properties::FloatProperty _rollAngleThreshold; properties::FloatProperty _orbitSpeedThreshold; - properties::FloatProperty _panSpeedThreshold; properties::FloatProperty _spinSensitivity; properties::FloatProperty _inputStillThreshold; properties::FloatProperty _centroidStillThreshold; diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h index d17313a9f9..645e8dc70a 100644 --- a/modules/touch/include/TouchMarker.h +++ b/modules/touch/include/TouchMarker.h @@ -44,7 +44,6 @@ namespace ghoul { namespace opengl { class ProgramObject; - class Texture; } // namespace opengl } // namespace ghoul @@ -60,14 +59,11 @@ class TouchMarker : public properties::PropertyOwner bool deinitialize(); void render(const std::vector list); - void update(); private: - void loadTexture(); void createVertexList(const std::vector list); - properties::StringProperty _texturePath; properties::BoolProperty _visible; properties::FloatProperty _radiusSize; properties::FloatProperty _transparency; @@ -75,13 +71,10 @@ class TouchMarker : public properties::PropertyOwner properties::Vec3Property _color; std::unique_ptr _shader; - std::unique_ptr _texture; GLuint _quad; GLuint _vertexPositionBuffer; int _numFingers; - - bool _textureIsDirty; }; } // openspace namespace diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index 7312f883dd..76136e3d8f 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -48,7 +48,10 @@ class TuioEar : public TUIO::TuioListener { delete _tuioClient; delete _oscReceiver; } - + + /** + * Callback functions, listens to the TUIO server + */ void addTuioObject(TUIO::TuioObject *tobj); void updateTuioObject(TUIO::TuioObject *tobj); void removeTuioObject(TUIO::TuioObject *tobj); @@ -63,9 +66,24 @@ class TuioEar : public TUIO::TuioListener { void refresh(TUIO::TuioTime frameTime); + /** + * Returns a list of all touch history that happened since the last frame + */ std::vector getInput(); + + /** + * Returns true if a tap occured since the last frame + */ bool tap(); + + /** + * Returns tap's cursor coordinates and time information + */ TUIO::TuioCursor getTap(); + + /** + * Clears the input list, function called after getInput() each frame + */ void clearInput(); private: @@ -78,6 +96,10 @@ class TuioEar : public TUIO::TuioListener { std::vector _list; + + /** + * A list that tracks all of the cursor ID's that got removed since last frame + */ std::vector _removeList; }; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index ccf78a52fd..c3a8808c38 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -60,22 +60,20 @@ TouchInteraction::TouchInteraction() : properties::PropertyOwner("TouchInteraction"), _origin("origin", "Origin", ""), _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), - _onlyPan("Toggle Panning Mode", "Toggle pan interaction on direct-manipulation three finger case (FOR FEEDBACK)", false), // temp _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), _reset("Default Values", "Reset all properties to default", false), _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), _deceleratesPerSecond("Decelerates per second", "Number of times velocity is decelerated per second", 240, 60, 300), _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), - _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.1, 0.0, 0.5), + _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.2, 0.0, 0.5), _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.025f, 0.0f, 0.05f), _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.005f, 0.0f, 0.01f), - _panSpeedThreshold("Activate pan spinning", "Threshold to activate pan spinning in direct-manipulation", 0.0005f, 0.0, 0.01), - _spinSensitivity("Sensitivity of Spinning", "Sensitivity of spinning in direct-manipulation", 1.0f, 0, 2), + _spinSensitivity("Sensitivity of spinning", "Sensitivity of spinning in direct-manipulation", 1.0f, 0, 2), _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0005f, 0, 0.001), _centroidStillThreshold("Centroid stationary", "Threshold for stationary centroid", 0.0018f, 0, 0.01), // used to void wrongly interpreted roll interactions _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.015f, 0, 0.1), - _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 1, 0, 5), + _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 3, 0, 5), _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.025, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), @@ -86,10 +84,8 @@ TouchInteraction::TouchInteraction() _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack{ 0.0 }, _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { - addProperty(_touchActive); // how do i hide this? - + addProperty(_touchActive); addProperty(_unitTest); - addProperty(_onlyPan); // temp addProperty(_reset); addProperty(_maxTapTime); addProperty(_deceleratesPerSecond); @@ -98,7 +94,6 @@ TouchInteraction::TouchInteraction() addProperty(_nodeRadiusThreshold); addProperty(_rollAngleThreshold); addProperty(_orbitSpeedThreshold); - addProperty(_panSpeedThreshold); addProperty(_spinSensitivity); addProperty(_inputStillThreshold); addProperty(_centroidStillThreshold); @@ -123,7 +118,6 @@ TouchInteraction::TouchInteraction() // Called each frame if there is any input void TouchInteraction::updateStateFromInput(const std::vector& list, std::vector& lastProcessed) { - //ghoul_precondition(!list.empty(), "List must not be empty"); if (_tap) { // check for doubletap if (_time.getSessionTime().getTotalMilliseconds() < _maxTapTime) { _doubleTap = true; @@ -144,12 +138,7 @@ void TouchInteraction::updateStateFromInput(const std::vector& list, } // evaluates if current frame is in directTouchMode (will if so be used next frame) - if (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()) { // needs better definition? - _directTouchMode = true; - } - else { - _directTouchMode = false; - } + _directTouchMode = (_currentRadius > _nodeRadiusThreshold && _selected.size() == list.size()); } } @@ -168,9 +157,9 @@ bool TouchInteraction::guiMode(const std::vector& list) { static_cast(100 * (pos.x / _guiButton.value().x)) << "%, " << static_cast(100 * (pos.y / _guiButton.value().y)) << "%)\n"); } else if (_guiON) { - OnScreenGUIModule::touchInput = { _guiON, pos, 1 }; + OnScreenGUIModule::touchInput = { _guiON, pos, 1 }; // emulate touch input as a mouse } - return _guiON; // return if consumed + return _guiON; } // Sets _vel to update _camera according to direct-manipulation (L2 error) @@ -257,17 +246,19 @@ void TouchInteraction::directControl(const std::vector& list) { dPar.assign(par, par + ptr->nDOF); for (int i = 0; i < ptr->nDOF; ++i) { + // Initial values h = 1e-8; lastG = 1; dPar.at(i) += h; f1 = ptr->distToMinimize(dPar.data(), x, fdata, lmstat); dPar.at(i) = par[i]; - for (int j = 0; j < 100; ++j) { // iterative process to find the minimum step h that gives a good gradient + // Iterative process to find the minimum step h that gives a good gradient + for (int j = 0; j < 100; ++j) { if ((f1 - f0) != 0 && lastG == 0) { // found minimum step size h // scale up to get a good initial guess value h *= scale * scale * scale; - // clamp max step size to a fraction of the incoming parameter + // clamp min step size to a fraction of the incoming parameter if (i == 2) { double epsilon = 1e-4; h = std::max(std::max(std::abs(dPar.at(i)), epsilon) * 0.01, h); // make sure incoming parameter is larger than 0 @@ -301,7 +292,7 @@ void TouchInteraction::directControl(const std::vector& list) { } } else if (ptr->nDOF == 6) { - for (int i = 0; i < ptr->nDOF; ++i) { // lock to only pan and zoom on 3 finger case + for (int i = 0; i < ptr->nDOF; ++i) { // lock to only pan and zoom on 3 finger case, no roll/orbit g[i] = (i == 2) ? g[i] : g[i] / std::abs(g[i]); } } @@ -322,6 +313,7 @@ void TouchInteraction::directControl(const std::vector& list) { par.at(0) = _lastVel.orbit.x; // use _lastVel for orbit par.at(1) = _lastVel.orbit.y; + // Parse input data to be used in the LM algorithm std::vector selectedPoints; std::vector screenPoints; for (const SelectedBody& sb : _selected) { @@ -330,11 +322,11 @@ void TouchInteraction::directControl(const std::vector& list) { std::vector::const_iterator c = find_if(list.begin(), list.end(), [&sb](const TuioCursor& c) { return c.getSessionID() == sb.id; }); screenPoints.push_back(glm::dvec2(2 * (c->getX() - 0.5), -2 * (c->getY() - 0.5))); // normalized -1 to 1 coordinates on screen } - FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, _selected.at(0).node, _lmstat, _onlyPan, _currentRadius }; + FunctionData fData = { selectedPoints, screenPoints, nDOF, castToNDC, distToMinimize, _camera, _selected.at(0).node, _lmstat, _currentRadius }; void* dataPtr = reinterpret_cast(&fData); - _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); // finds best transform values and stores them in par - //std::cout << "Levmarq success after " << _lmstat.final_it << " iterations\n"; + // finds best transform values for the new camera state and stores them in par + _lmSuccess = levmarq(nDOF, par.data(), nFingers, NULL, distToMinimize, gradient, dataPtr, &_lmstat); if (_lmSuccess && !_unitTest) { // if good values were found set new camera state _vel.orbit = glm::dvec2(par.at(0), par.at(1)); @@ -342,20 +334,20 @@ void TouchInteraction::directControl(const std::vector& list) { _vel.zoom = par.at(2); _vel.roll = par.at(3); if (nDOF > 4) { - if (_onlyPan) { - _vel.roll = 0.0; - } + _vel.roll = 0.0; _vel.pan = glm::dvec2(par.at(4), par.at(5)); } } step(1.0); + + // Reset velocities after setting new camera state _lastVel = _vel; _vel.orbit = glm::dvec2(0.0, 0.0); _vel.zoom = 0.0; _vel.roll = 0.0; _vel.pan = glm::dvec2(0.0, 0.0); } - else { // prevents touch to infinitely be active (due to windows bridge case where event doesnt get consumed) + else { // prevents touch to infinitely be active (due to windows bridge case where event doesnt get consumed sometimes when LMA fails to converge) OnScreenGUIModule::touchInput = { 1, glm::dvec2(0.0, 0.0), 1 }; } } @@ -411,26 +403,17 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { } } } - } _selected = newSelected; - - //debugging - /*for (auto it : newSelected) { - std::cout << it.node->name() << " hit with cursor " << it.id << ". Surface Coordinates: " << glm::to_string(it.coordinates) - << "\n"; - }*/ } // Interprets the input gesture to a specific interaction int TouchInteraction::interpretInteraction(const std::vector& list, const std::vector& lastProcessed) { - //ghoul_precondition(!list.empty(), "List must not be empty"); - glm::dvec3 lastCentroid = _centroid; _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); - // see if the distance between fingers changed + // see if the distance between fingers changed - used in pan interpretation double dist = 0; double lastDist = 0; TuioCursor cursor = list.at(0); @@ -443,7 +426,7 @@ int TouchInteraction::interpretInteraction(const std::vector& list, lastDist += glm::length(glm::dvec2(p.second.getX(), p.second.getY()) - glm::dvec2(point.getX(), point.getY())); point = p.second; } - // find the slowest moving finger + // find the slowest moving finger - used in roll interpretation double minDiff = 1000; int id = 0; for (const TuioCursor& c : list) { @@ -458,7 +441,7 @@ int TouchInteraction::interpretInteraction(const std::vector& list, id = c.getSessionID(); } } - // find if all fingers angles are high + // find if all fingers angles are high - used in roll interpretation double rollOn = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = 0.0; @@ -483,7 +466,8 @@ int TouchInteraction::interpretInteraction(const std::vector& list, return ROT; } else { - if (std::abs(dist - lastDist) / list.at(0).getMotionSpeed() < _interpretPan && list.size() == 3) { // if distance between fingers is constant we have panning + // if average distance between 3 fingers are constant we have panning + if (std::abs(dist - lastDist) / list.at(0).getMotionSpeed() < _interpretPan && list.size() == 3) { return PAN; } // we have roll if one finger is still, or the total roll angles around the centroid is over _rollAngleThreshold (_centroidStillThreshold is used to void misinterpretations) @@ -501,13 +485,12 @@ void TouchInteraction::computeVelocities(const std::vector& list, co TuioCursor cursor = list.at(0); int action = interpretInteraction(list, lastProcessed); - switch (action) { case ROT: { // add rotation velocity _vel.orbit += glm::dvec2(cursor.getXSpeed() * _sensitivity.orbit.x, cursor.getYSpeed() * _sensitivity.orbit.y); break; } - case PINCH: { // add zooming velocity + case PINCH: { // add zooming velocity - dependant on distance difference between contact points this/last frame double distance = std::accumulate(list.begin(), list.end(), 0.0, [&](double d, const TuioCursor& c) { return d + c.getDistance(_centroid.x, _centroid.y); }) / list.size(); @@ -525,6 +508,7 @@ void TouchInteraction::computeVelocities(const std::vector& list, co double res = diff; double lastAngle = point.getAngle(_centroid.x, _centroid.y); double currentAngle = c.getAngle(_centroid.x, _centroid.y); + // if's used to set angles 359 + 1 = 0 and 0 - 1 = 359 if (lastAngle > currentAngle + 1.5 * M_PI) res += currentAngle + (2 * M_PI - lastAngle); else if (currentAngle > lastAngle + 1.5 * M_PI) @@ -544,9 +528,9 @@ void TouchInteraction::computeVelocities(const std::vector& list, co case PICK: { // pick something in the scene as focus node if (_selected.size() == 1 && _selected.at(0).node) { setFocusNode(_selected.at(0).node); - OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode since TouchInteraction is not subclass of InteractionMode + OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode() since TouchInteraction is not subclass of InteractionMode - // rotate camera to look at new focus + // rotate camera to look at new focus, using slerp quat glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); glm::dvec3 camForward = glm::normalize(_camera->viewDirectionWorldSpace()); double angle = glm::angle(camForward, camToFocus); @@ -557,9 +541,9 @@ void TouchInteraction::computeVelocities(const std::vector& list, co _toSlerp.w = cos(angle / 2.0); _slerpdT = 0.0; } - else { // should zoom in to current but not too much + else { // zooms in to current if PICK interpret happened but only space was selected double dist = glm::distance(_camera->positionVec3(), _camera->focusPositionVec3()) - _focusNode->boundingSphere(); - _vel.zoom = (_sensitivity.zoom * std::max(_touchScreenSize.value() * 0.1, 1.0)) * _tapZoomFactor * dist; // this should not be based on dt + _vel.zoom = (_sensitivity.zoom * std::max(_touchScreenSize.value() * 0.1, 1.0)) * _tapZoomFactor * dist; } break; } @@ -655,13 +639,6 @@ void TouchInteraction::step(double dt) { void TouchInteraction::unitTest() { if (_unitTest) { _lmstat.verbose = true; - // time set and paused in .scene file - //openspace.time.setTime("2016 SEP 8 23:00:00.500") - //openspace.time.togglePause() - - // set camera pos and rot - //_camera->setPositionVec3(glm::dvec3(26974419543.178154, 76302892465.068359, -127116625827.843369)); - //_camera->setRotation(glm::dquat(0.791502, -0.576456, -0.001228, -0.203029)); // set _selected pos and new pos (on screen) std::vector lastFrame = { @@ -697,12 +674,20 @@ void TouchInteraction::unitTest() { } } -// Decelerate velocities (set 0 for directTouch) +/* Decelerate velocities, called a set number of times per second to dereference it from frame time +* Example: +* Assume: frequency = 0.01, dt = 0.05 (200 fps), _timeSlack = 0.0001 +* times = floor((0.05 + 0.0001) / 0.01) = 5 +* _timeSlack = 0.0501 % 0.01 = 0.01 +*/ void TouchInteraction::decelerate(double dt) { double frequency = 1.0 / _deceleratesPerSecond; + // Number of times velocities should decelerate, depending on chosen frequency and time slack over from last frame int times = (dt + _timeSlack) / frequency; + // Save the new time slack for the next frame _timeSlack = fmod((dt + _timeSlack), frequency); + // Decelerate zoom velocity quicker if we're close enough to use direct-manipulation if (!_directTouchMode && _currentRadius > _nodeRadiusThreshold && _vel.zoom > _focusNode->boundingSphere()) { _vel.zoom *= std::pow(1 - 2 * _friction.value().y, times); } @@ -714,17 +699,13 @@ void TouchInteraction::decelerate(double dt) { // Called if all fingers are off the screen void TouchInteraction::resetAfterInput() { - //ghoul_postcondition(_selected.empty(), "Selected list must be empty after reset"); - //_directTouchMode = false; if (_directTouchMode && _selected.size() > 0 && _lmSuccess) { double spinDelta = _spinSensitivity / OsEng.windowWrapper().averageDeltaTime(); - if (glm::length(_lastVel.pan) > _panSpeedThreshold) { // might not be desired - _vel.pan = _lastVel.pan * spinDelta; - } - else if (glm::length(_lastVel.orbit) > _orbitSpeedThreshold) { // good value to activate "spinning" + if (glm::length(_lastVel.orbit) > _orbitSpeedThreshold) { // allow node to start "spinning" after direct-manipulation finger is let go off _vel.orbit = _lastVel.orbit * spinDelta; } } + // Reset emulated mouse values if (_guiON) { bool activeLastFrame = OnScreenGUIModule::touchInput.action; OnScreenGUIModule::touchInput.active = false; @@ -739,32 +720,33 @@ void TouchInteraction::resetAfterInput() { } _lmSuccess = true; + // Ensure that _guiON is consistent with properties in OnScreenGUI and _guiON = OnScreenGUIModule::gui.isEnabled(); + // Reset variables _lastVel.orbit = glm::dvec2(0.0, 0.0); _lastVel.zoom = 0.0; _lastVel.roll = 0.0; _lastVel.pan = glm::dvec2(0.0, 0.0); - _selected.clear(); // should clear if no longer have a direct-touch input + _selected.clear(); } +// Reset all property values to default void TouchInteraction::resetToDefault() { _unitTest.set(false); - _onlyPan.set(false); // temp _reset.set(false); _maxTapTime.set(300); _deceleratesPerSecond.set(240); _touchScreenSize.set(55.0f); - _tapZoomFactor.set(0.1f); + _tapZoomFactor.set(0.2f); _nodeRadiusThreshold.set(0.2f); _rollAngleThreshold.set(0.025f); _orbitSpeedThreshold.set(0.005f); - _panSpeedThreshold.set(0.0005f); _spinSensitivity.set(1.0f); _inputStillThreshold.set(0.0005f); _centroidStillThreshold.set(0.0018f); _interpretPan.set(0.015f); - _slerpTime.set(1.0f); + _slerpTime.set(3.0f); _guiButton.set(glm::ivec2(32, 64)); _friction.set(glm::vec4(0.01, 0.025, 0.02, 0.02)); } @@ -772,6 +754,7 @@ void TouchInteraction::resetToDefault() { void TouchInteraction::tap() { _tap = true; } + void TouchInteraction::touchActive(bool active) { _touchActive = active; } @@ -780,6 +763,7 @@ void TouchInteraction::touchActive(bool active) { Camera* TouchInteraction::getCamera() { return _camera; } + SceneGraphNode* TouchInteraction::getFocusNode() { return _focusNode; } diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index 6cbf67277f..30860fe0ee 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -27,10 +27,7 @@ #include #include #include -#include #include -#include -#include #include @@ -53,10 +50,7 @@ TouchMarker::TouchMarker() glm::vec3(0.f), glm::vec3(1.f) ) - , _texturePath("texturePath", "Color Texture") , _shader(nullptr) - , _texture(nullptr) - , _textureIsDirty(false) , _numFingers(0) { addProperty(_visible); @@ -65,9 +59,6 @@ TouchMarker::TouchMarker() addProperty(_thickness); _color.setViewOption(properties::Property::ViewOptions::Color); addProperty(_color); - addProperty(_texturePath); - _texturePath.onChange(std::bind(&TouchMarker::loadTexture, this)); - //_texturePath.set("?"); } @@ -84,10 +75,7 @@ bool TouchMarker::initialize() { catch (const ghoul::opengl::ShaderObject::ShaderCompileError& e) { LERRORC(e.component, e.what()); } - - //loadTexture(); - - return (_shader != nullptr); // && _texture; + return (_shader != nullptr); } bool TouchMarker::deinitialize() { @@ -97,14 +85,11 @@ bool TouchMarker::deinitialize() { glDeleteBuffers(1, &_vertexPositionBuffer); _vertexPositionBuffer = 0; - _texture = nullptr; - RenderEngine& renderEngine = OsEng.renderEngine(); if (_shader) { renderEngine.removeRenderProgram(_shader); _shader = nullptr; } - return true; } @@ -113,11 +98,6 @@ void TouchMarker::render(const std::vector list) { createVertexList(list); _shader->activate(); - // Bind texture - /*ghoul::opengl::TextureUnit unit; - unit.activate(); - _texture->bind(); - _shader->setUniform("texture1", unit);*/ _shader->setUniform("radius", _radiusSize); _shader->setUniform("transparency", _transparency); _shader->setUniform("thickness", _thickness); @@ -135,31 +115,6 @@ void TouchMarker::render(const std::vector list) { } } -void TouchMarker::update() { - if (_shader->isDirty()) - _shader->rebuildFromFile(); - - if (_textureIsDirty) { - loadTexture(); - _textureIsDirty = false; - } -} - -void TouchMarker::loadTexture() { - if (_texturePath.value() != "") { - _texture = ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath)); - - if (_texture) { - LDEBUGC( - "TouchMarker", - "Loaded texture from '" << absPath(_texturePath) << "'" - ); - _texture->uploadTexture(); - _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); // linear or mipmap? - } - } -} - void TouchMarker::createVertexList(const std::vector list) { _numFingers = list.size(); GLfloat vertexData[MAX_FINGERS]; diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index adab44040f..3511d3d0b9 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -87,6 +87,8 @@ void TuioEar::updateTuioCursor(TuioCursor *tcur) { void TuioEar::removeTuioCursor(TuioCursor *tcur) { _mx.lock(); _removeList.push_back(tcur->getSessionID()); + + // Check if the cursor ID could be considered a tap double dist = 0; for (const TuioPoint& p : tcur->getPath()) { dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY())); @@ -128,6 +130,7 @@ TuioCursor TuioEar::getTap() { return _tapCo; } +// Removes all cursor ID from list that exists in _removeList void TuioEar::clearInput() { _mx.lock(); _list.erase( @@ -149,6 +152,7 @@ void TuioEar::clearInput() { _mx.unlock(); } +// Standard UDP IP connection to port 3333 TuioEar::TuioEar() { _oscReceiver = new UdpReceiver(3333); _tuioClient = new TuioClient(_oscReceiver); diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index ab1826948e..3b223cbad0 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -50,7 +50,7 @@ bool TouchModule::hasNewInput() { // Get new input from listener listOfContactPoints = ear.getInput(); ear.clearInput(); - touch.touchActive(!listOfContactPoints.empty()); + touch.touchActive(!listOfContactPoints.empty()); // Set touch property to active (to void mouse input, mainly for mtdev bridges) // Erase old input id's that no longer exists lastProcessed.erase( @@ -67,7 +67,7 @@ bool TouchModule::hasNewInput() { ) == listOfContactPoints.end(); }), lastProcessed.end()); - // Tap + // if tap occured, we have new input if (listOfContactPoints.empty() && lastProcessed.empty() && ear.tap()) { TuioCursor c = ear.getTap(); listOfContactPoints.push_back(c); @@ -79,12 +79,12 @@ bool TouchModule::hasNewInput() { // Return true if we got new input if (listOfContactPoints.size() == lastProcessed.size() && !listOfContactPoints.empty()) { bool newInput = true; - // @COMMENT Why can you use for_each without std:: ? It seems like there is a using namespace std somewhere + // go through list and check if the last registrered time is newer than the one in lastProcessed (last frame) std::for_each(lastProcessed.begin(), lastProcessed.end(), [this, &newInput](Point& p) { - std::vector::iterator cursor = find_if(listOfContactPoints.begin(), listOfContactPoints.end(), + std::vector::iterator cursor = std::find_if(listOfContactPoints.begin(), listOfContactPoints.end(), [&p](const TuioCursor& c) { return c.getSessionID() == p.first; }); double now = cursor->getPath().back().getTuioTime().getTotalMilliseconds(); - if (!cursor->isMoving()) { + if (!cursor->isMoving()) { // if current cursor isn't moving, we want to interpret that as new input for interaction purposes newInput = true; } else if (p.second.getTuioTime().getTotalMilliseconds() == now) { @@ -138,15 +138,18 @@ TouchModule::TouchModule() for (const TuioCursor& c : listOfContactPoints) { lastProcessed.emplace_back(c.getSessionID(), c.getPath().back()); } - touch.unitTest(); - touch.step(OsEng.windowWrapper().deltaTime()); + touch.unitTest(); // used to save data from solver, only calculated for one frame when user chooses in GUI + touch.step(OsEng.windowWrapper().deltaTime()); // calculate the new camera state for this frame } ); OsEng.registerModuleCallback( + // This is done in the PostDraw phase so that it will render it on top of + // everything else in the case of fisheyes. With this being in the Render callback + // the markers would be rendered on top of each of the cube faces OpenSpaceEngine::CallbackOption::PostDraw, [&]() { - markers.render(listOfContactPoints); + markers.render(listOfContactPoints); // render markers, customizable through the GUI } ); } diff --git a/modules/touch/touchmodule.h b/modules/touch/touchmodule.h index 1bcd88b49f..ca3fb93faf 100644 --- a/modules/touch/touchmodule.h +++ b/modules/touch/touchmodule.h @@ -38,6 +38,9 @@ namespace openspace { TouchModule(); private: + /** + * Returns true if new touch input occured since the last frame + */ bool hasNewInput(); TuioEar ear; diff --git a/openspace.cfg b/openspace.cfg index 2f5d727c33..cca4d91e1b 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -7,12 +7,12 @@ return { -- occurs in a single window, a fisheye projection, or a dome cluster system -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, + --SGCTConfig = sgct.config.single{}, -- SGCTConfig = sgct.config.single{res={1920, 1080}, shared=true}, -- A regular 1920x1080 window - --SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, + SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, From f94d58d7388efc40f55bc994eea190a56b3b9004 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 21 Jun 2017 11:30:16 -0600 Subject: [PATCH 131/192] improvement to tap interpretation by time instead of path size --- modules/touch/src/TuioEar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 3511d3d0b9..2645473c3a 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -94,7 +94,8 @@ void TuioEar::removeTuioCursor(TuioCursor *tcur) { dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY())); } dist /= tcur->getPath().size(); - if (tcur->getPath().size() < 7 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) { + double heldTime = tcur->getPath().back().getTuioTime().getTotalMilliseconds() - tcur->getPath().front().getTuioTime().getTotalMilliseconds(); + if (heldTime < 180 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) { _tapCo = TuioCursor(*tcur); _tap = true; } From 7bb83abe086a584e64773c633ecc669d18507830 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Wed, 21 Jun 2017 11:31:04 -0600 Subject: [PATCH 132/192] constructor looks more clean --- modules/touch/src/TouchInteraction.cpp | 52 +++++++++++++------------- modules/touch/src/TouchMarker.cpp | 2 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index c3a8808c38..2bbf6c55d5 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -57,32 +57,32 @@ using namespace TUIO; namespace openspace { TouchInteraction::TouchInteraction() - : properties::PropertyOwner("TouchInteraction"), - _origin("origin", "Origin", ""), - _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false), - _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden), - _reset("Default Values", "Reset all properties to default", false), - _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000), - _deceleratesPerSecond("Decelerates per second", "Number of times velocity is decelerated per second", 240, 60, 300), - _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f), - _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.2, 0.0, 0.5), - _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f), - _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.025f, 0.0f, 0.05f), - _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.005f, 0.0f, 0.01f), - _spinSensitivity("Sensitivity of spinning", "Sensitivity of spinning in direct-manipulation", 1.0f, 0, 2), - _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0005f, 0, 0.001), - _centroidStillThreshold("Centroid stationary", "Threshold for stationary centroid", 0.0018f, 0, 0.01), // used to void wrongly interpreted roll interactions - _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.015f, 0, 0.1), - _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 3, 0, 5), - _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)), - _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.025, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)), + : properties::PropertyOwner("TouchInteraction") + , _origin("origin", "Origin", "") + , _unitTest("Click to take a unit test", "Take a unit test saving the LM data into file", false) + , _touchActive("TouchEvents", "True if we have a touch event", false, properties::Property::Visibility::Hidden) + , _reset("Default Values", "Reset all properties to default", false) + , _maxTapTime("Max Tap Time", "Max tap delay (in ms) for double tap", 300, 10, 1000) + , _deceleratesPerSecond("Decelerates per second", "Number of times velocity is decelerated per second", 240, 60, 300) + , _touchScreenSize("TouchScreenSize", "Touch Screen size in inches", 55.0f, 5.5f, 150.0f) + , _tapZoomFactor("Tap zoom factor","Scaling distance travelled on tap", 0.2, 0.0, 0.5) + , _nodeRadiusThreshold("Activate direct-manipulation", "Radius a planet has to have to activate direct-manipulation", 0.2f, 0.0f, 1.0f) + , _rollAngleThreshold("Interpret roll", "Threshold for min angle for roll interpret", 0.025f, 0.0f, 0.05f) + , _orbitSpeedThreshold("Activate orbit spinning", "Threshold to activate orbit spinning in direct-manipulation", 0.005f, 0.0f, 0.01f) + , _spinSensitivity("Sensitivity of spinning", "Sensitivity of spinning in direct-manipulation", 1.0f, 0, 2) + , _inputStillThreshold("Input still", "Threshold for interpreting input as still", 0.0005f, 0, 0.001) + , _centroidStillThreshold("Centroid stationary", "Threshold for stationary centroid", 0.0018f, 0, 0.01) // used to void wrongly interpreted roll interactions + , _interpretPan("Pan delta distance", "Delta distance between fingers allowed for interpreting pan interaction", 0.015f, 0, 0.1) + , _slerpTime("Time to slerp", "Time to slerp in seconds to new orientation with new node picking", 3, 0, 5) + , _guiButton("GUI Button", "GUI button size in pixels.", glm::ivec2(32, 64), glm::ivec2(8, 16), glm::ivec2(128, 256)) + , _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.025, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)) - _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) }, - _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) }, - _centroid{ glm::dvec3(0.0) }, - _projectionScaleFactor{ 1.000004 }, // calculated with two vectors with known diff in length, then projDiffLength/diffLength. - _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack{ 0.0 }, - _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } + , _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) } + , _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) } + , _centroid{ glm::dvec3(0.0) } + , _projectionScaleFactor{ 1.000004 } // calculated with two vectors with known diff in length, then projDiffLength/diffLength. + , _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack{ 0.0 } + , _directTouchMode{ false }, _tap{ false }, _doubleTap{ false }, _lmSuccess{ true }, _guiON{ false } { addProperty(_touchActive); addProperty(_unitTest); @@ -504,7 +504,7 @@ void TouchInteraction::computeVelocities(const std::vector& list, co } case ROLL: { // add global roll rotation velocity double rollFactor = std::accumulate(list.begin(), list.end(), 0.0, [&](double diff, const TuioCursor& c) { - TuioPoint point = find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; + TuioPoint point = std::find_if(lastProcessed.begin(), lastProcessed.end(), [&c](const Point& p) { return p.first == c.getSessionID(); })->second; double res = diff; double lastAngle = point.getAngle(_centroid.x, _centroid.y); double currentAngle = c.getAngle(_centroid.x, _centroid.y); diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index 30860fe0ee..dc7e1cb6e4 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -42,7 +42,7 @@ TouchMarker::TouchMarker() , _visible("TouchMarkers visible", "Toggle visibility of markers", true) , _radiusSize("Marker size", "Marker radius", 30, 0, 100) , _transparency("Transparency of marker", "Marker transparency", 0.8, 0, 1.0) - , _thickness("Thickness of marker", "Marker thickness", 1.0, 0, 4.0) + , _thickness("Thickness of marker", "Marker thickness", 2.0, 0, 4.0) , _color( "MarkerColor", "Marker color", From 5caf871e06625021b27aa359fa2e9c9721cec8b4 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Fri, 23 Jun 2017 15:24:07 -0600 Subject: [PATCH 133/192] improve LMA converging ability on zoom cases and limit max iterations to 3k instead of 5k --- modules/touch/ext/levmarq.cpp | 2 +- modules/touch/src/TouchInteraction.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/touch/ext/levmarq.cpp b/modules/touch/ext/levmarq.cpp index 89ee28bd2a..0777743d12 100644 --- a/modules/touch/ext/levmarq.cpp +++ b/modules/touch/ext/levmarq.cpp @@ -31,7 +31,7 @@ OTHER DEALINGS IN THE SOFTWARE. // set parameters required by levmarq() to default values void levmarq_init(LMstat *lmstat) { lmstat->verbose = false; - lmstat->max_it = 5000; + lmstat->max_it = 3000; lmstat->init_lambda = 1e-6; lmstat->up_factor = 10; lmstat->down_factor = 10; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 2bbf6c55d5..505f21adb6 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -260,8 +260,8 @@ void TouchInteraction::directControl(const std::vector& list) { // clamp min step size to a fraction of the incoming parameter if (i == 2) { - double epsilon = 1e-4; - h = std::max(std::max(std::abs(dPar.at(i)), epsilon) * 0.01, h); // make sure incoming parameter is larger than 0 + double epsilon = 1e-3; + h = std::max(std::max(std::abs(dPar.at(i)), epsilon) * 0.001, h); // make sure incoming parameter is larger than 0 } else if (ptr->nDOF == 2) { h = std::max(std::abs(dPar.at(i)) * 0.001, h); @@ -349,6 +349,7 @@ void TouchInteraction::directControl(const std::vector& list) { } else { // prevents touch to infinitely be active (due to windows bridge case where event doesnt get consumed sometimes when LMA fails to converge) OnScreenGUIModule::touchInput = { 1, glm::dvec2(0.0, 0.0), 1 }; + resetAfterInput(); } } @@ -472,7 +473,7 @@ int TouchInteraction::interpretInteraction(const std::vector& list, } // we have roll if one finger is still, or the total roll angles around the centroid is over _rollAngleThreshold (_centroidStillThreshold is used to void misinterpretations) else if (std::abs(minDiff) < _inputStillThreshold || (std::abs(rollOn) < 100.0 && glm::distance(_centroid, lastCentroid) / list.size() < _centroidStillThreshold)) { - return ROLL; // also interpret if angles are high + return ROLL; } else { return PINCH; From 81164e0d8d2777ee7d01216d29006c8f2897fa01 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Mon, 3 Jul 2017 13:46:17 -0600 Subject: [PATCH 134/192] Stub for Performance Manager & GUI Button --- include/openspace/performance/performancemanager.h | 1 + modules/onscreengui/src/guiperformancecomponent.cpp | 4 ++++ src/performance/performancemanager.cpp | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index 55fca53f5b..7d6e43dddd 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -58,6 +58,7 @@ public: void storeIndividualPerformanceMeasurement(std::string identifier, long long nanoseconds); void storeScenePerformanceMeasurements(const std::vector& sceneNodes); + void outputLogs(); PerformanceLayout* performanceData(); private: diff --git a/modules/onscreengui/src/guiperformancecomponent.cpp b/modules/onscreengui/src/guiperformancecomponent.cpp index 93be7203c5..ec6e31ee85 100644 --- a/modules/onscreengui/src/guiperformancecomponent.cpp +++ b/modules/onscreengui/src/guiperformancecomponent.cpp @@ -87,6 +87,10 @@ void GuiPerformanceComponent::render() { if (ImGui::Button("Reset measurements")) { OsEng.renderEngine().performanceManager()->resetPerformanceMeasurements(); } + + if (ImGui::Button("Output Logs")) { + OsEng.renderEngine().performanceManager()->outputLogs(); + } if (_sceneGraphIsEnabled) { bool sge = _sceneGraphIsEnabled; diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index d37b26a753..3540c6055c 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -196,6 +196,10 @@ bool PerformanceManager::isMeasuringPerformance() const { return _doPerformanceMeasurements; } +void PerformanceManager::outputLogs() { + for (size_t i = 0; i < 30; i++) LINFO("Outputting logs"); +} + PerformanceLayout* PerformanceManager::performanceData() { void* ptr = _performanceMemory->memory(); return reinterpret_cast(ptr); From 1d9bb740f26642f05b1eabe0d924f702f3341f55 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Mon, 3 Jul 2017 14:43:18 -0600 Subject: [PATCH 135/192] Some clarification & iteration fixes. --- src/performance/performancemanager.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index 3540c6055c..2a0a13cb15 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -197,7 +197,9 @@ bool PerformanceManager::isMeasuringPerformance() const { } void PerformanceManager::outputLogs() { - for (size_t i = 0; i < 30; i++) LINFO("Outputting logs"); + for (auto it = individualPerformanceLocations.begin(); it != individualPerformanceLocations.end(); ++it) { + LINFO("Log Count:" << it->second << " Node: " << it->first); + } } PerformanceLayout* PerformanceManager::performanceData() { @@ -265,40 +267,43 @@ void PerformanceManager::storeScenePerformanceMeasurements( SceneGraphNode::PerformanceRecord r = node->performanceRecord(); PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[i]; + // Covert milliseconds to seconds + const float second = 1000.f; + std::rotate( std::begin(entry.renderTime), std::next(std::begin(entry.renderTime)), std::end(entry.renderTime) ); - entry.renderTime[PerformanceLayout::NumberValues - 1] = r.renderTime / 1000.f; + entry.renderTime[PerformanceLayout::NumberValues - 1] = r.renderTime / second; std::rotate( std::begin(entry.updateTranslation), std::next(std::begin(entry.updateTranslation)), std::end(entry.updateTranslation) ); - entry.updateTranslation[PerformanceLayout::NumberValues - 1] = r.updateTimeTranslation / 1000.f; + entry.updateTranslation[PerformanceLayout::NumberValues - 1] = r.updateTimeTranslation / second; std::rotate( std::begin(entry.updateRotation), std::next(std::begin(entry.updateRotation)), std::end(entry.updateRotation) ); - entry.updateRotation[PerformanceLayout::NumberValues - 1] = r.updateTimeRotation / 1000.f; + entry.updateRotation[PerformanceLayout::NumberValues - 1] = r.updateTimeRotation / second; std::rotate( std::begin(entry.updateScaling), std::next(std::begin(entry.updateScaling)), std::end(entry.updateScaling) ); - entry.updateScaling[PerformanceLayout::NumberValues - 1] = r.updateTimeScaling / 1000.f; + entry.updateScaling[PerformanceLayout::NumberValues - 1] = r.updateTimeScaling / second; std::rotate( std::begin(entry.updateRenderable), std::next(std::begin(entry.updateRenderable)), std::end(entry.updateRenderable) ); - entry.updateRenderable[PerformanceLayout::NumberValues - 1] = r.updateTimeRenderable / 1000.f; + entry.updateRenderable[PerformanceLayout::NumberValues - 1] = r.updateTimeRenderable / second; } _performanceMemory->releaseLock(); } From 9015a8dad94781484a801be790320cf14160c7ac Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Wed, 5 Jul 2017 15:31:09 -0600 Subject: [PATCH 136/192] Example of access to invidvidual performance statistics --- src/performance/performancemanager.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index 2a0a13cb15..c6d612c3f9 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -197,9 +197,20 @@ bool PerformanceManager::isMeasuringPerformance() const { } void PerformanceManager::outputLogs() { + LINFO("Logging from " << typeid(*this).name() << "::" << __func__); for (auto it = individualPerformanceLocations.begin(); it != individualPerformanceLocations.end(); ++it) { LINFO("Log Count:" << it->second << " Node: " << it->first); } + + PerformanceLayout* layout = performanceData(); + + for (size_t i = 0; i < layout->nFunctionEntries; ++i) { + LINFO("Log:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->functionEntries[i].time[0]); + } + + for (size_t i = 0; i < layout->nScaleGraphEntries; ++i) { + LINFO("Log:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->sceneGraphEntries[i].renderTime[0];); + } } PerformanceLayout* PerformanceManager::performanceData() { From 810c2ec4930531443dee85d2014ce8ce2be8ffee Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Thu, 6 Jul 2017 12:07:50 -0600 Subject: [PATCH 137/192] Enable PerformanceManager logging with ImGui checkbox. --- .../performance/performancemanager.h | 12 +++++- .../src/guiperformancecomponent.cpp | 11 +++-- src/performance/performancemanager.cpp | 43 ++++++++++++++++--- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index 7d6e43dddd..0a81730837 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -59,14 +59,24 @@ public: void storeScenePerformanceMeasurements(const std::vector& sceneNodes); void outputLogs(); - PerformanceLayout* performanceData(); + void enableLogging(); + void disableLogging(); + void toggleLogging(); + void setLogging(bool enabled); + bool loggingEnabled(); + PerformanceLayout* performanceData(); private: bool _doPerformanceMeasurements; + bool _loggingEnabled; std::map individualPerformanceLocations; std::unique_ptr _performanceMemory; + + size_t _tick; + + void tick(); }; } // namespace performance diff --git a/modules/onscreengui/src/guiperformancecomponent.cpp b/modules/onscreengui/src/guiperformancecomponent.cpp index ec6e31ee85..0fcd10a22f 100644 --- a/modules/onscreengui/src/guiperformancecomponent.cpp +++ b/modules/onscreengui/src/guiperformancecomponent.cpp @@ -81,17 +81,16 @@ void GuiPerformanceComponent::render() { v = _functionsIsEnabled; ImGui::Checkbox("Functions", &v); _functionsIsEnabled = v; - + v = OsEng.renderEngine().performanceManager()->loggingEnabled(); + ImGui::Checkbox("Output Logs", &v); + OsEng.renderEngine().performanceManager()->setLogging(v); + ImGui::Spacing(); - + if (ImGui::Button("Reset measurements")) { OsEng.renderEngine().performanceManager()->resetPerformanceMeasurements(); } - if (ImGui::Button("Output Logs")) { - OsEng.renderEngine().performanceManager()->outputLogs(); - } - if (_sceneGraphIsEnabled) { bool sge = _sceneGraphIsEnabled; ImGui::Begin("SceneGraph", &sge); diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index c6d612c3f9..9fa1b48c25 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -130,6 +130,8 @@ void PerformanceManager::destroyGlobalSharedMemory() { PerformanceManager::PerformanceManager() : _performanceMemory(nullptr) + , _tick(0) + , _loggingEnabled(false) { using ghoul::SharedMemory; PerformanceManager::createGlobalSharedMemory(); @@ -213,11 +215,34 @@ void PerformanceManager::outputLogs() { } } +void PerformanceManager::enableLogging() { + setLogging(true); +} + +void PerformanceManager::disableLogging() { + setLogging(false); +} + +void PerformanceManager::toggleLogging() { + _loggingEnabled = !_loggingEnabled; +} +void PerformanceManager::setLogging(bool enabled) { + _loggingEnabled = enabled; +} + +bool PerformanceManager::loggingEnabled() { + return _loggingEnabled; +} + PerformanceLayout* PerformanceManager::performanceData() { void* ptr = _performanceMemory->memory(); return reinterpret_cast(ptr); } +void PerformanceManager::tick() { + _tick = (_tick + 1) % PerformanceLayout::NumberValues; +} + void PerformanceManager::storeIndividualPerformanceMeasurement (std::string identifier, long long microseconds) { @@ -278,45 +303,49 @@ void PerformanceManager::storeScenePerformanceMeasurements( SceneGraphNode::PerformanceRecord r = node->performanceRecord(); PerformanceLayout::SceneGraphPerformanceLayout& entry = layout->sceneGraphEntries[i]; - // Covert milliseconds to seconds - const float second = 1000.f; + // Covert nano to microseconds + const float micro = 1000.f; std::rotate( std::begin(entry.renderTime), std::next(std::begin(entry.renderTime)), std::end(entry.renderTime) ); - entry.renderTime[PerformanceLayout::NumberValues - 1] = r.renderTime / second; + entry.renderTime[PerformanceLayout::NumberValues - 1] = r.renderTime / micro; std::rotate( std::begin(entry.updateTranslation), std::next(std::begin(entry.updateTranslation)), std::end(entry.updateTranslation) ); - entry.updateTranslation[PerformanceLayout::NumberValues - 1] = r.updateTimeTranslation / second; + entry.updateTranslation[PerformanceLayout::NumberValues - 1] = r.updateTimeTranslation / micro; std::rotate( std::begin(entry.updateRotation), std::next(std::begin(entry.updateRotation)), std::end(entry.updateRotation) ); - entry.updateRotation[PerformanceLayout::NumberValues - 1] = r.updateTimeRotation / second; + entry.updateRotation[PerformanceLayout::NumberValues - 1] = r.updateTimeRotation / micro; std::rotate( std::begin(entry.updateScaling), std::next(std::begin(entry.updateScaling)), std::end(entry.updateScaling) ); - entry.updateScaling[PerformanceLayout::NumberValues - 1] = r.updateTimeScaling / second; + entry.updateScaling[PerformanceLayout::NumberValues - 1] = r.updateTimeScaling / micro; std::rotate( std::begin(entry.updateRenderable), std::next(std::begin(entry.updateRenderable)), std::end(entry.updateRenderable) ); - entry.updateRenderable[PerformanceLayout::NumberValues - 1] = r.updateTimeRenderable / second; + entry.updateRenderable[PerformanceLayout::NumberValues - 1] = r.updateTimeRenderable / micro; } _performanceMemory->releaseLock(); + + if (_loggingEnabled && _tick == PerformanceLayout::NumberValues - 1) outputLogs(); + + tick(); } } // namespace performance From a91e48efe74696504abbcf46b3da90601eb30f4d Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Thu, 6 Jul 2017 17:01:21 -0600 Subject: [PATCH 138/192] Add PerformanceMeasurement logging variables to ConfigurationManager. Read from logDir and file prefix from config file in PerformanceManager. --- .../openspace/engine/configurationmanager.h | 4 ++++ .../performance/performancemanager.h | 9 +++++++ src/engine/configurationmanager.cpp | 3 +++ src/engine/configurationmanager_doc.inl | 12 ++++++++++ src/performance/performancemanager.cpp | 24 +++++++++++++++++-- src/rendering/renderengine.cpp | 8 +++++++ 6 files changed, 58 insertions(+), 2 deletions(-) diff --git a/include/openspace/engine/configurationmanager.h b/include/openspace/engine/configurationmanager.h index 8ec3aa167d..3a6e34a47a 100644 --- a/include/openspace/engine/configurationmanager.h +++ b/include/openspace/engine/configurationmanager.h @@ -78,12 +78,16 @@ public: static const std::string KeySettingsScript; /// The key that stores the settings for determining log-related settings static const std::string KeyLogging; + /// The key that stores the directory for Logging + static const std::string PartLogDir; /// The key that stores the desired LogLevel for the whole application /// \sa ghoul::logging::LogManager static const std::string PartLogLevel; /// The key that stores whether the log should be immediately flushed after a n /// \sa ghoul::logging::LogManager static const std::string PartImmediateFlush; + /// The key for prefixing PerformanceMeasurement logfiles + static const std::string PartLogPerformancePrefix; /// The key that stores a subdirectory with a description for additional /// ghoul::logging::Log%s to be created /// \sa LogFactory diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index 0a81730837..a12c967f56 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -59,6 +59,12 @@ public: void storeScenePerformanceMeasurements(const std::vector& sceneNodes); void outputLogs(); + + void logDir(std::string dir); + std::string logDir(); + void prefix(std::string prefix); + std::string prefix(); + void enableLogging(); void disableLogging(); void toggleLogging(); @@ -69,6 +75,9 @@ public: private: bool _doPerformanceMeasurements; bool _loggingEnabled; + + std::string _logDir; + std::string _prefix; std::map individualPerformanceLocations; diff --git a/src/engine/configurationmanager.cpp b/src/engine/configurationmanager.cpp index 17bb3e8afd..3800d83f8a 100644 --- a/src/engine/configurationmanager.cpp +++ b/src/engine/configurationmanager.cpp @@ -62,8 +62,11 @@ const string ConfigurationManager::KeyConfigScene = "Scene"; const string ConfigurationManager::KeyConfigTask = "Task"; const string ConfigurationManager::KeyLogging = "Logging"; +const string ConfigurationManager::PartLogDir = "LogDir"; const string ConfigurationManager::PartLogLevel = "LogLevel"; const string ConfigurationManager::PartImmediateFlush = "ImmediateFlush"; +const string ConfigurationManager::PartLogPerformancePrefix = "PerformancePrefix"; + const string ConfigurationManager::PartLogs = "Logs"; const string ConfigurationManager::PartAppend = "Append"; const string ConfigurationManager::PartCapabilitiesVerbosity = "CapabilitiesVerbosity"; diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index e955c50c75..cda32562bf 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -86,6 +86,18 @@ documentation::Documentation ConfigurationManager::Documentation() { { ConfigurationManager::KeyLogging, new TableVerifier({ + { + ConfigurationManager::PartLogDir, + new StringVerifier, + "The directory for logs", + Optional::Yes + }, + { + ConfigurationManager::PartLogPerformancePrefix, + new StringVerifier, + "A string to prefix PerformanceMeasurement logfiles", + Optional::Yes + }, { ConfigurationManager::PartLogLevel, new StringInListVerifier( diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index 9fa1b48c25..f8e761aaa5 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -132,6 +133,8 @@ PerformanceManager::PerformanceManager() : _performanceMemory(nullptr) , _tick(0) , _loggingEnabled(false) + , _logDir(absPath("${BASE_PATH}")) + , _prefix("PM-") { using ghoul::SharedMemory; PerformanceManager::createGlobalSharedMemory(); @@ -207,14 +210,31 @@ void PerformanceManager::outputLogs() { PerformanceLayout* layout = performanceData(); for (size_t i = 0; i < layout->nFunctionEntries; ++i) { - LINFO("Log:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->functionEntries[i].time[0]); + LINFO("LogA:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->functionEntries[i].time[0]); } + LINFO("Log Dir: " << absPath(_logDir + "/" + _prefix)); for (size_t i = 0; i < layout->nScaleGraphEntries; ++i) { - LINFO("Log:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->sceneGraphEntries[i].renderTime[0];); + LINFO("LogB:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->sceneGraphEntries[i].renderTime[0];); } } +void PerformanceManager::logDir(std::string dir) { + _logDir = absPath(dir); +} + +std::string PerformanceManager::logDir() { + return _logDir; +} + +void PerformanceManager::prefix(std::string prefix) { + _prefix = prefix; +} + +std::string PerformanceManager::prefix() { + return _prefix; +} + void PerformanceManager::enableLogging() { setLogging(true); } diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 51daf34c9d..65314e2d71 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -134,6 +134,14 @@ RenderEngine::RenderEngine() if (_performanceMeasurements) { if (!_performanceManager) { _performanceManager = std::make_unique(); + const std::string KeyLogDir = ConfigurationManager::KeyLogging + "." + ConfigurationManager::PartLogDir; + const std::string KeyPrefix = ConfigurationManager::KeyLogging + "." + ConfigurationManager::PartLogPerformancePrefix; + if (OsEng.configurationManager().hasKeyAndValue(KeyLogDir)) { + _performanceManager->logDir(OsEng.configurationManager().value(KeyLogDir)); + } + if (OsEng.configurationManager().hasKeyAndValue(KeyPrefix)) { + _performanceManager->prefix(OsEng.configurationManager().value(KeyPrefix)); + } } } else { From a165af8c59876042c53c2de54010bbe97f7bba8b Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Thu, 6 Jul 2017 18:34:38 -0600 Subject: [PATCH 139/192] Output to files. Function files aren't writing for some reason. --- .../performance/performancemanager.h | 6 +- src/performance/performancemanager.cpp | 56 +++++++++++++++++-- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index a12c967f56..b7ffd0f321 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -59,7 +59,9 @@ public: void storeScenePerformanceMeasurements(const std::vector& sceneNodes); void outputLogs(); - + + void writeData(std::ofstream& out, const std::vector data); + void logDir(std::string dir); std::string logDir(); void prefix(std::string prefix); @@ -78,6 +80,8 @@ private: std::string _logDir; std::string _prefix; + std::string _suffix; + std::string _ext; std::map individualPerformanceLocations; diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index f8e761aaa5..0db76fd3cb 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -34,6 +34,8 @@ #include #include +#include +#include namespace { const char* _loggerCat = "PerformanceManager"; @@ -135,6 +137,8 @@ PerformanceManager::PerformanceManager() , _loggingEnabled(false) , _logDir(absPath("${BASE_PATH}")) , _prefix("PM-") + , _suffix("") + , _ext("log") { using ghoul::SharedMemory; PerformanceManager::createGlobalSharedMemory(); @@ -202,23 +206,63 @@ bool PerformanceManager::isMeasuringPerformance() const { } void PerformanceManager::outputLogs() { - LINFO("Logging from " << typeid(*this).name() << "::" << __func__); + + // Log individual performance locations first for (auto it = individualPerformanceLocations.begin(); it != individualPerformanceLocations.end(); ++it) { LINFO("Log Count:" << it->second << " Node: " << it->first); } + // Log Layout values PerformanceLayout* layout = performanceData(); - for (size_t i = 0; i < layout->nFunctionEntries; ++i) { - LINFO("LogA:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->functionEntries[i].time[0]); + // Log function performance + for (size_t n = 0; n < layout->nFunctionEntries; n++) { + const auto function = layout->functionEntries[n]; + LINFO("LogC:" << function.name << " " << layout->functionEntries[n].time[0]); + // Open file + std::string filename = _logDir + "/" + _prefix + "FUNCTION-" + function.name + _suffix + "." + _ext; + std::replace(filename.begin(), filename.end(), ':', '-'); + LINFO("FILE: " << filename); + std::ofstream out = std::ofstream(absPath(filename)); + + // Comma separate data + for (size_t i = 0; i < PerformanceLayout::NumberValues; i++) { + const std::vector data = { function.time[i] }; + writeData(out, data); + } + out.close(); } - LINFO("Log Dir: " << absPath(_logDir + "/" + _prefix)); - for (size_t i = 0; i < layout->nScaleGraphEntries; ++i) { - LINFO("LogB:" << i << " Node: " << layout->sceneGraphEntries[i].name << " " << layout->sceneGraphEntries[i].renderTime[0];); + // Log scene object performance + for (size_t n = 0; n < layout->nScaleGraphEntries; n++) { + const auto node = layout->sceneGraphEntries[n]; + + // Open file + const std::string filename = _logDir + "/" + _prefix + "NODE-" + node.name + _suffix + "." + _ext; + std::ofstream out = std::ofstream(absPath(filename)); + + // Comma separate data + for (size_t i = 0; i < PerformanceLayout::NumberValues; i++) { + const std::vector data = { + node.renderTime[i], + node.updateRenderable[i], + node.updateRotation[i], + node.updateScaling[i], + node.updateTranslation[i] + }; + writeData(out, data); + } + out.close(); } } +void PerformanceManager::writeData(std::ofstream& out, const std::vector data) { + for (size_t i = 0; i < data.size() - 1; i++) { + out << data[i] << ","; + } + out << data[data.size() - 1] << "\n"; +} + void PerformanceManager::logDir(std::string dir) { _logDir = absPath(dir); } From 115bb998c977b4c36979e1d8ffce85c44aea8d0e Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Fri, 7 Jul 2017 10:44:16 -0600 Subject: [PATCH 140/192] Remove colons and cat filename together with formatLogName. --- .../performance/performancemanager.h | 2 ++ src/performance/performancemanager.cpp | 19 ++++++++----------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index b7ffd0f321..6033a1e4c7 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -62,6 +62,8 @@ public: void writeData(std::ofstream& out, const std::vector data); + const std::string formatLogName(std::string nodeName); + void logDir(std::string dir); std::string logDir(); void prefix(std::string prefix); diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index 0db76fd3cb..a7eda9c963 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -207,22 +207,13 @@ bool PerformanceManager::isMeasuringPerformance() const { void PerformanceManager::outputLogs() { - // Log individual performance locations first - for (auto it = individualPerformanceLocations.begin(); it != individualPerformanceLocations.end(); ++it) { - LINFO("Log Count:" << it->second << " Node: " << it->first); - } - // Log Layout values PerformanceLayout* layout = performanceData(); // Log function performance for (size_t n = 0; n < layout->nFunctionEntries; n++) { const auto function = layout->functionEntries[n]; - LINFO("LogC:" << function.name << " " << layout->functionEntries[n].time[0]); - // Open file - std::string filename = _logDir + "/" + _prefix + "FUNCTION-" + function.name + _suffix + "." + _ext; - std::replace(filename.begin(), filename.end(), ':', '-'); - LINFO("FILE: " << filename); + const std::string filename = formatLogName(function.name); std::ofstream out = std::ofstream(absPath(filename)); // Comma separate data @@ -238,7 +229,7 @@ void PerformanceManager::outputLogs() { const auto node = layout->sceneGraphEntries[n]; // Open file - const std::string filename = _logDir + "/" + _prefix + "NODE-" + node.name + _suffix + "." + _ext; + const std::string filename = formatLogName(node.name); std::ofstream out = std::ofstream(absPath(filename)); // Comma separate data @@ -263,6 +254,12 @@ void PerformanceManager::writeData(std::ofstream& out, const std::vector out << data[data.size() - 1] << "\n"; } +const std::string PerformanceManager::formatLogName(std::string nodeName) { + // Replace any colons with dashes + std::replace(nodeName.begin(), nodeName.end(), ':', '-'); + return _logDir + "/" + _prefix + nodeName + _suffix + "." + _ext; +} + void PerformanceManager::logDir(std::string dir) { _logDir = absPath(dir); } From 29fd158ed52b6331c2761038b594ab20305d1651 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Fri, 7 Jul 2017 12:33:49 -0600 Subject: [PATCH 141/192] Create BoolProperty for PerformanceComponent --- modules/onscreengui/include/guiperformancecomponent.h | 1 + modules/onscreengui/src/guiperformancecomponent.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/onscreengui/include/guiperformancecomponent.h b/modules/onscreengui/include/guiperformancecomponent.h index f81a072639..55827e3007 100644 --- a/modules/onscreengui/include/guiperformancecomponent.h +++ b/modules/onscreengui/include/guiperformancecomponent.h @@ -54,6 +54,7 @@ protected: properties::BoolProperty _sceneGraphIsEnabled; properties::BoolProperty _functionsIsEnabled; + properties::BoolProperty _outputLogs; }; } // namespace gui diff --git a/modules/onscreengui/src/guiperformancecomponent.cpp b/modules/onscreengui/src/guiperformancecomponent.cpp index 0fcd10a22f..4e8771d726 100644 --- a/modules/onscreengui/src/guiperformancecomponent.cpp +++ b/modules/onscreengui/src/guiperformancecomponent.cpp @@ -59,11 +59,13 @@ GuiPerformanceComponent::GuiPerformanceComponent() , _sortingSelection("sortingSelection", "Sorting", -1, -1, 6) , _sceneGraphIsEnabled("showSceneGraph", "Show Scene Graph Measurements", false) , _functionsIsEnabled("showFunctions", "Show Function Measurements", false) + , _outputLogs("outputLogs", "Output Logs", false) { addProperty(_sortingSelection); addProperty(_sceneGraphIsEnabled); addProperty(_functionsIsEnabled); + addProperty(_outputLogs); } void GuiPerformanceComponent::render() { @@ -81,9 +83,10 @@ void GuiPerformanceComponent::render() { v = _functionsIsEnabled; ImGui::Checkbox("Functions", &v); _functionsIsEnabled = v; - v = OsEng.renderEngine().performanceManager()->loggingEnabled(); + v = _outputLogs; ImGui::Checkbox("Output Logs", &v); OsEng.renderEngine().performanceManager()->setLogging(v); + _outputLogs = v; ImGui::Spacing(); From f1d468dd3a97c3b74ce9bca4cfa42059e1704d3d Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Fri, 7 Jul 2017 12:52:55 -0600 Subject: [PATCH 142/192] Appending to logs now instead of overwriting :-/ --- src/performance/performancemanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index a7eda9c963..6368ee352e 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -214,7 +214,7 @@ void PerformanceManager::outputLogs() { for (size_t n = 0; n < layout->nFunctionEntries; n++) { const auto function = layout->functionEntries[n]; const std::string filename = formatLogName(function.name); - std::ofstream out = std::ofstream(absPath(filename)); + std::ofstream out = std::ofstream(absPath(filename), std::ofstream::out | std::ofstream::app); // Comma separate data for (size_t i = 0; i < PerformanceLayout::NumberValues; i++) { @@ -230,7 +230,7 @@ void PerformanceManager::outputLogs() { // Open file const std::string filename = formatLogName(node.name); - std::ofstream out = std::ofstream(absPath(filename)); + std::ofstream out = std::ofstream(absPath(filename), std::ofstream::out | std::ofstream::app); // Comma separate data for (size_t i = 0; i < PerformanceLayout::NumberValues; i++) { From 0f34b055124e01eafcad915e0a8b65d8990dffbf Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 8 Jul 2017 12:40:52 -0400 Subject: [PATCH 143/192] Increasing warning level --- Jenkinsfile | 160 +- apps/OpenSpace/main.cpp | 1316 ++++---- ext/ghoul | 2 +- modules/globebrowsing/other/pixelbuffer.cpp | 168 +- modules/globebrowsing/other/pixelbuffer.h | 280 +- .../other/pixelbuffercontainer.h | 230 +- .../other/pixelbuffercontainer.inl | 260 +- .../gdalrawtiledatareader.cpp | 678 ++-- .../tile/rawtiledatareader/tiledatatype.cpp | 1228 +++---- .../tile/rawtiledatareader/tiledatatype.h | 122 +- modules/globebrowsing/tile/textureformat.h | 86 +- .../tile/tiletextureinitdata.cpp | 304 +- .../globebrowsing/tile/tiletextureinitdata.h | 182 +- .../newhorizons/util/projectioncomponent.cpp | 1900 +++++------ modules/space/rendering/renderableplanet.cpp | 1126 +++---- modules/volume/rawvolumewriter.h | 114 +- src/engine/openspaceengine.cpp | 2892 ++++++++--------- src/engine/wrapper/sgctwindowwrapper.cpp | 496 +-- src/rendering/framebufferrenderer.cpp | 1056 +++--- src/util/syncbuffer.cpp | 124 +- support/cmake/support_macros.cmake | 1098 ++++--- 21 files changed, 6926 insertions(+), 6896 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 1985a6a989..8454bd82fc 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,80 +1,80 @@ -def modules = [ - "base", - "debugging", - "fieldlines", - "galaxy", - "globebrowsing", - "iswa", - "kameleon", - "kameleonvolume", - "multiresvolume", - "newhorizons", - "onscreengui", - "space", - "toyvolume", - "volume" -]; - -def flags = "-DGHOUL_USE_DEVIL=OFF " - -for (module in modules) { - flags += "-DOPENSPACE_OPENSPACE_MODULE_" + module.toUpperCase() + "=ON " -} - -echo flags - -stage('Build') { - parallel linux: { - node('linux') { - timeout(time: 30, unit: 'MINUTES') { - checkout scm - sh 'git submodule update --init --recursive' - sh ''' - mkdir -p build - cd build - cmake .. ''' + - flags + ''' .. - make - ''' - } - } - }, - windows: { - node('windows') { - timeout(time: 30, unit: 'MINUTES') { - checkout scm - bat ''' - git submodule update --init --recursive - if not exist "build" mkdir "build" - cd build - cmake -G "Visual Studio 15 2017 Win64" .. ''' + - flags + ''' .. - msbuild.exe OpenSpace.sln /nologo /verbosity:minimal /m:2 /p:Configuration=Debug - ''' - } - } - }, - osx: { - node('osx') { - timeout(time: 30, unit: 'MINUTES') { - checkout scm - sh 'git submodule update --init --recursive' - sh ''' - export PATH=${PATH}:/usr/local/bin:/Applications/CMake.app/Contents/bin - export CMAKE_BUILD_TOOL=/Applications/CMake.app/Contents/bin/CMake - srcDir=$PWD - if [ ! -d ${srcDir} ]; then - mkdir ${srcDir} - fi - if [ ! -d ${srcDir}/build ]; then - mkdir ${srcDir}/build - fi - cd ${srcDir}/build - /Applications/CMake.app/Contents/bin/cmake -G Xcode -D NASM=/usr/local/bin/nasm ${srcDir} .. ''' + - flags + ''' - xcodebuild -quiet - ''' - } - } - } -} +def modules = [ + "base", + "debugging", + "fieldlines", + "galaxy", + "globebrowsing", + "iswa", + "kameleon", + "kameleonvolume", + "multiresvolume", + "newhorizons", + "onscreengui", + "space", + "toyvolume", + "volume" +]; + +def flags = "-DGHOUL_USE_DEVIL=OFF " + +for (module in modules) { + flags += "-DOPENSPACE_OPENSPACE_MODULE_" + module.toUpperCase() + "=ON " +} + +echo flags + +stage('Build') { + parallel linux: { + node('linux') { + timeout(time: 30, unit: 'MINUTES') { + checkout scm + sh 'git submodule update --init --recursive' + sh ''' + mkdir -p build + cd build + cmake .. ''' + + flags + ''' .. + make + ''' + } + } + }, + windows: { + node('windows') { + timeout(time: 30, unit: 'MINUTES') { + checkout scm + bat ''' + git submodule update --init --recursive + if not exist "build" mkdir "build" + cd build + cmake -G "Visual Studio 15 2017 Win64" .. ''' + + flags + ''' .. + msbuild.exe OpenSpace.sln /nologo /verbosity:minimal /m:2 /p:Configuration=Debug + ''' + } + } + }, + osx: { + node('osx') { + timeout(time: 30, unit: 'MINUTES') { + checkout scm + sh 'git submodule update --init --recursive' + sh ''' + export PATH=${PATH}:/usr/local/bin:/Applications/CMake.app/Contents/bin + export CMAKE_BUILD_TOOL=/Applications/CMake.app/Contents/bin/CMake + srcDir=$PWD + if [ ! -d ${srcDir} ]; then + mkdir ${srcDir} + fi + if [ ! -d ${srcDir}/build ]; then + mkdir ${srcDir}/build + fi + cd ${srcDir}/build + /Applications/CMake.app/Contents/bin/cmake -G Xcode -D NASM=/usr/local/bin/nasm ${srcDir} .. ''' + + flags + ''' + xcodebuild -quiet + ''' + } + } + } +} diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 6ee55bb774..c280bef68e 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -1,658 +1,658 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include -#include - -#include -#include -//#include - -#include - -#ifdef WIN32 - -#include - -#include -#include - -#include - -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable : 4091) -#include -#pragma warning (pop) -#endif // _MSC_VER - -#endif // WIN32 - -#ifdef OPENVR_SUPPORT -#include -#endif // OPENVR_SUPPORT - -#ifdef OPENSPACE_HAS_SPOUT -#include "SpoutLibrary.h" -#endif // OPENSPACE_HAS_SPOUT - - -#define DEVELOPER_MODE - -namespace { - -const char* _loggerCat = "main"; -sgct::Engine* SgctEngine; - -const char* OpenVRTag = "OpenVR"; -const char* SpoutTag = "Spout"; - -#ifdef WIN32 - -LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) { - SYSTEMTIME stLocalTime; - GetLocalTime(&stLocalTime); - - - LFATAL("Printing Stack Trace that lead to the crash:"); - std::vector stackTrace = ghoul::stackTrace(); - for (const std::string& s : stackTrace) { - LINFO(s); - } - - std::string dumpFile = fmt::format( - "OpenSpace_{}_{}_{}-{}-{}-{}-{}-{}-{}--{}--{}.dmp", - openspace::OPENSPACE_VERSION_MAJOR, - openspace::OPENSPACE_VERSION_MINOR, - openspace::OPENSPACE_VERSION_PATCH, - stLocalTime.wYear, - stLocalTime.wMonth, - stLocalTime.wDay, - stLocalTime.wHour, - stLocalTime.wMinute, - stLocalTime.wSecond, - GetCurrentProcessId(), - GetCurrentThreadId() - ); - - LINFO("Creating dump file: " << dumpFile); - - HANDLE hDumpFile = CreateFile( - dumpFile.c_str(), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_WRITE | FILE_SHARE_READ, - 0, - CREATE_ALWAYS, - 0, - 0 - ); - - MINIDUMP_EXCEPTION_INFORMATION exceptionParameter; - exceptionParameter.ThreadId = GetCurrentThreadId(); - exceptionParameter.ExceptionPointers = exceptionPointers; - exceptionParameter.ClientPointers = TRUE; - - BOOL success = MiniDumpWriteDump( - GetCurrentProcess(), - GetCurrentProcessId(), - hDumpFile, - MiniDumpWithDataSegs, - &exceptionParameter, - nullptr, - nullptr - ); - - if (success) { - LINFO("Created successfully"); - } - else { - LERROR("Dumpfile created unsuccessfully"); - } - - return EXCEPTION_EXECUTE_HANDLER; -} - -#endif // WIN32 - -#ifdef OPENVR_SUPPORT -sgct::SGCTWindow* FirstOpenVRWindow = nullptr; -#endif - -#ifdef OPENSPACE_HAS_SPOUT -/** - * This struct stores all information about a single render window. Depending on the - * frame setup, each window can be mono or stereo, the information of which is stored in - * the \c leftOrMain and \c right members respectively. - */ -struct SpoutWindow { - struct SpoutData { - SPOUTHANDLE handle = nullptr; - bool initialized = false; - }; - - /// The left framebuffer (or main, if there is no stereo rendering) - SpoutData leftOrMain; - - /// The right framebuffer - SpoutData right; - - /// The window ID of this windows - size_t windowId = size_t(-1); -}; - -/// The list of all windows with spout senders -std::vector SpoutWindows; - -#endif // OPENSPACE_HAS_SPOUT - - - -std::pair supportedOpenGLVersion() { - // Just create a window in order to retrieve the available OpenGL version before we - // create the real window - glfwInit(); - - // On OS X we need to explicitly set the version and specify that we are using CORE - // profile to be able to use glGetIntegerv(GL_MAJOR_VERSION, &major) and - // glGetIntegerv(GL_MINOR_VERSION, &minor) explicitly setting to OGL 3.3 CORE works - // since all Mac's now support at least 3.3 -#ifdef __APPLE__ - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#endif - - glfwWindowHint(GLFW_VISIBLE, GL_FALSE); - - // By creating an offscreen window, the user will not know that we created this window - GLFWwindow* offscreen = glfwCreateWindow(128, 128, "", nullptr, nullptr); - glfwMakeContextCurrent(offscreen); - - // Get the OpenGL version - int major, minor; - glGetIntegerv(GL_MAJOR_VERSION, &major); - glGetIntegerv(GL_MINOR_VERSION, &minor); - - // And get rid of the window again - glfwDestroyWindow(offscreen); - glfwWindowHint(GLFW_VISIBLE, GL_TRUE); - - return { major, minor }; -} - -void mainInitFunc() { - LTRACE("main::mainInitFunc(begin)"); - - LDEBUG("Initializing OpenSpace Engine started"); - OsEng.initialize(); - LDEBUG("Initializing OpenSpace Engine finished"); - - LDEBUG("Initializing OpenGL in OpenSpace Engine started"); - OsEng.initializeGL(); - LDEBUG("Initializing OpenGL in OpenSpace Engine finished"); - - // Find if we have at least one OpenVR window - // Save reference to first OpenVR window, which is the one we will copy to the HMD. - for (size_t i = 0; i < SgctEngine->getNumberOfWindows(); ++i) { - if (SgctEngine->getWindowPtr(i)->checkIfTagExists(OpenVRTag)) { -#ifdef OPENVR_SUPPORT - FirstOpenVRWindow = SgctEngine->getWindowPtr(i); - - // If we have an OpenVRWindow, initialize OpenVR. - sgct::SGCTOpenVR::initialize( - SgctEngine->getNearClippingPlane(), SgctEngine->getFarClippingPlane() - ); -#else - LWARNING( - "OpenVR was requested, but OpenSpace was compiled without VR support." - ); -#endif - - break; - } - } - - // Set the clear color for all non-linear projection viewports - // @CLEANUP: Why is this necessary? We can set the clear color in the configuration - // files --- abock - const size_t nWindows = SgctEngine->getNumberOfWindows(); - for (size_t i = 0; i < nWindows; ++i) { - sgct::SGCTWindow* w = SgctEngine->getWindowPtr(i); - const size_t nViewports = w->getNumberOfViewports(); - for (size_t j = 0; j < nViewports; ++j) { - sgct_core::Viewport* v = w->getViewport(j); - ghoul_assert(v != nullptr, "Number of reported viewports was incorrect"); - sgct_core::NonLinearProjection* p = v->getNonLinearProjectionPtr(); - if (p) { - p->setClearColor(glm::vec4(0.f, 0.f, 0.f, 1.f)); - } - } - } - - for (size_t i = 0; i < nWindows; ++i) { - const sgct::SGCTWindow* windowPtr = SgctEngine->getWindowPtr(i); - - if (!windowPtr->checkIfTagExists(SpoutTag)) { - continue; - } - -#ifdef OPENSPACE_HAS_SPOUT - SpoutWindow w; - - w.windowId = i; - - const sgct::SGCTWindow::StereoMode sm = windowPtr->getStereoMode(); - const bool hasStereo = - (sm != sgct::SGCTWindow::No_Stereo) && - (sm < sgct::SGCTWindow::Side_By_Side_Stereo); - - if (hasStereo) { - SpoutWindow::SpoutData& left = w.leftOrMain; - left.handle = GetSpout(); - left.initialized = left.handle->CreateSender( - (windowPtr->getName() + "_left").c_str(), - windowPtr->getXFramebufferResolution(), - windowPtr->getYFramebufferResolution() - ); - - SpoutWindow::SpoutData& right = w.right; - right.handle = GetSpout(); - right.initialized = right.handle->CreateSender( - (windowPtr->getName() + "_right").c_str(), - windowPtr->getXFramebufferResolution(), - windowPtr->getYFramebufferResolution() - ); - } - else { - SpoutWindow::SpoutData& main = w.leftOrMain; - main.handle = GetSpout(); - main.initialized = main.handle->CreateSender( - windowPtr->getName().c_str(), - windowPtr->getXFramebufferResolution(), - windowPtr->getYFramebufferResolution() - ); - } - - SpoutWindows.push_back(std::move(w)); -#else - LWARNING( - "Spout was requested, but OpenSpace was compiled without Spout support." - ); - -#endif // OPENSPACE_HAS_SPOUT - } - LTRACE("main::mainInitFunc(end)"); -} - -void mainPreSyncFunc() { - LTRACE("main::mainPreSyncFunc(begin)"); - OsEng.setRunTime(sgct::Engine::getTime()); - OsEng.preSynchronization(); - LTRACE("main::mainPreSyncFunc(end)"); -} - -void mainPostSyncPreDrawFunc() { - LTRACE("main::postSynchronizationPreDraw(begin)"); - OsEng.postSynchronizationPreDraw(); - -#ifdef OPENVR_SUPPORT - if (FirstOpenVRWindow) { - // Update pose matrices for all tracked OpenVR devices once per frame - sgct::SGCTOpenVR::updatePoses(); - } -#endif // OPENVR_SUPPORT - - LTRACE("main::postSynchronizationPreDraw(end)"); -} - -void mainRenderFunc() { - LTRACE("main::mainRenderFunc(begin)"); - - glm::mat4 viewMatrix = - SgctEngine->getCurrentViewMatrix() * - // User matrix - glm::translate( - glm::mat4(1.f), - SgctEngine->getDefaultUserPtr()->getPos() - ) - ; - - glm::mat4 projectionMatrix = SgctEngine->getCurrentProjectionMatrix(); -#ifdef OPENVR_SUPPORT - bool currentWindowIsHMD = FirstOpenVRWindow == SgctEngine->getCurrentWindowPtr(); - if (sgct::SGCTOpenVR::isHMDActive() && currentWindowIsHMD) { - projectionMatrix = sgct::SGCTOpenVR::getHMDCurrentViewProjectionMatrix( - SgctEngine->getCurrentFrustumMode() - ); - } -#endif - - OsEng.render( - SgctEngine->getModelMatrix(), - viewMatrix, - projectionMatrix - ); - LTRACE("main::mainRenderFunc(end)"); -} - -void mainPostDrawFunc() { - LTRACE("main::mainPostDrawFunc(begin)"); - -#ifdef OPENVR_SUPPORT - if (FirstOpenVRWindow) { - // Copy the first OpenVR window to the HMD - sgct::SGCTOpenVR::copyWindowToHMD(FirstOpenVRWindow); - } -#endif // OPENVR_SUPPORT - - OsEng.postDraw(); - -#ifdef OPENSPACE_HAS_SPOUT - for (const SpoutWindow& w : SpoutWindows) { - sgct::SGCTWindow* window = SgctEngine->getWindowPtr(w.windowId); - if (w.leftOrMain.initialized) { - GLuint texId = window->getFrameBufferTexture(sgct::Engine::LeftEye); - glBindTexture(GL_TEXTURE_2D, texId); - w.leftOrMain.handle->SendTexture( - texId, - GL_TEXTURE_2D, - window->getXFramebufferResolution(), - window->getYFramebufferResolution() - ); - } - - if (w.right.initialized) { - GLuint texId = window->getFrameBufferTexture(sgct::Engine::RightEye); - glBindTexture(GL_TEXTURE_2D, texId); - w.right.handle->SendTexture( - texId, - GL_TEXTURE_2D, - window->getXFramebufferResolution(), - window->getYFramebufferResolution() - ); - } - } - glBindTexture(GL_TEXTURE_2D, 0); -#endif // OPENSPACE_HAS_SPOUT - - LTRACE("main::mainPostDrawFunc(end)"); -} - -void mainExternalControlCallback(const char* receivedChars, int size) { - LTRACE("main::mainExternalControlCallback(begin)"); - if (SgctEngine->isMaster()) { - OsEng.externalControlCallback(receivedChars, size, 0); - } - LTRACE("main::mainExternalControlCallback(end)"); -} - -void mainKeyboardCallback(int key, int, int action, int mods) { - LTRACE("main::mainKeyboardCallback(begin)"); - if (SgctEngine->isMaster()) { - OsEng.keyboardCallback( - openspace::Key(key), - openspace::KeyModifier(mods), - openspace::KeyAction(action) - ); - } - LTRACE("main::mainKeyboardCallback(begin)"); -} - -void mainMouseButtonCallback(int key, int action) { - LTRACE("main::mainMouseButtonCallback(begin)"); - if (SgctEngine->isMaster()) { - OsEng.mouseButtonCallback( - openspace::MouseButton(key), - openspace::MouseAction(action) - ); - } - LTRACE("main::mainMouseButtonCallback(end)"); -} - -void mainMousePosCallback(double x, double y) { - if (SgctEngine->isMaster()) { - OsEng.mousePositionCallback(x, y); - } -} - -void mainMouseScrollCallback(double, double posY) { - LTRACE("main::mainMouseScrollCallback(begin"); - if (SgctEngine->isMaster()) { - OsEng.mouseScrollWheelCallback(posY); - } - LTRACE("main::mainMouseScrollCallback(end)"); -} - -void mainCharCallback(unsigned int codepoint, int mods) { - if (SgctEngine->isMaster()) { - OsEng.charCallback(codepoint, openspace::KeyModifier(mods)); - } -} - -void mainEncodeFun() { - LTRACE("main::mainEncodeFun(begin)"); - OsEng.encode(); - LTRACE("main::mainEncodeFun(end)"); -} - -void mainDecodeFun() { - LTRACE("main::mainDecodeFun(begin)"); - OsEng.decode(); - LTRACE("main::mainDecodeFun(end)"); -} - -void mainLogCallback(const char* msg) { - std::string message = msg; - if (message.empty() || message == ".") { - // We don't want the empty '.' message that SGCT sends while it is waiting for - // connections from other network nodes - return; - } - // Remove the trailing \n that is passed along - LINFOC("SGCT", message.substr(0, message.size() - 1)); -} - -int main_main(int argc, char** argv) { - std::pair glVersion = supportedOpenGLVersion(); - - // Create the OpenSpace engine and get arguments for the SGCT engine - // @CLEANUP: Replace the return valua with throwing an exception --abock - std::vector sgctArguments; - bool requestQuit = false; - openspace::OpenSpaceEngine::create( - argc, argv, - std::make_unique(), - sgctArguments, - requestQuit - ); - - if (requestQuit) { - return EXIT_SUCCESS; - } - - LINFO("Detected OpenGL version: " << glVersion.first << "." << glVersion.second); - - // Create sgct engine c arguments - int newArgc = static_cast(sgctArguments.size()); - - char** newArgv = new char*[newArgc]; - for (int i = 0; i < newArgc; ++i) { - newArgv[i] = const_cast(sgctArguments.at(i).c_str()); - } - - // Need to set this before the creation of the sgct::Engine - sgct::MessageHandler::instance()->setLogToConsole(false); - sgct::MessageHandler::instance()->setShowTime(false); - sgct::MessageHandler::instance()->setLogToCallback(true); - sgct::MessageHandler::instance()->setLogCallback(mainLogCallback); - -#ifdef __APPLE__ - glfwWindowHint(GLFW_STENCIL_BITS, 8); -#endif - - LDEBUG("Creating SGCT Engine"); - SgctEngine = new sgct::Engine(newArgc, newArgv); - - // Deallocate sgct c arguments - delete[] newArgv; - - // Bind functions - SgctEngine->setInitOGLFunction(mainInitFunc); - SgctEngine->setPreSyncFunction(mainPreSyncFunc); - SgctEngine->setPostSyncPreDrawFunction(mainPostSyncPreDrawFunc); - SgctEngine->setDrawFunction(mainRenderFunc); - SgctEngine->setPostDrawFunction(mainPostDrawFunc); - SgctEngine->setKeyboardCallbackFunction(mainKeyboardCallback); - SgctEngine->setMouseButtonCallbackFunction(mainMouseButtonCallback); - SgctEngine->setMousePosCallbackFunction(mainMousePosCallback); - SgctEngine->setMouseScrollCallbackFunction(mainMouseScrollCallback); - SgctEngine->setExternalControlCallback(mainExternalControlCallback); - SgctEngine->setCharCallbackFunction(mainCharCallback); - - // Disable the immediate exit of the application when the ESC key is pressed - SgctEngine->setExitKey(SGCT_KEY_UNKNOWN); - - sgct::MessageHandler::instance()->setNotifyLevel(sgct::MessageHandler::NOTIFY_ALL); - - // Set encode and decode functions - // NOTE: starts synchronizing before init functions - sgct::SharedData::instance()->setEncodeFunction(mainEncodeFun); - sgct::SharedData::instance()->setDecodeFunction(mainDecodeFun); - - // Try to open a window - LDEBUG("Initialize SGCT Engine"); - std::map, sgct::Engine::RunMode> versionMapping = { - { { 3, 3 }, sgct::Engine::RunMode::OpenGL_3_3_Core_Profile }, - { { 4, 0 }, sgct::Engine::RunMode::OpenGL_4_0_Core_Profile }, - { { 4, 1 }, sgct::Engine::RunMode::OpenGL_4_1_Core_Profile }, - { { 4, 2 }, sgct::Engine::RunMode::OpenGL_4_2_Core_Profile }, - { { 4, 3 }, sgct::Engine::RunMode::OpenGL_4_3_Core_Profile }, - { { 4, 4 }, sgct::Engine::RunMode::OpenGL_4_4_Core_Profile }, - { { 4, 5 }, sgct::Engine::RunMode::OpenGL_4_5_Core_Profile } - }; - ghoul_assert( - versionMapping.find(glVersion) != versionMapping.end(), - "Unknown OpenGL version. Missing statement in version mapping map" - ); - - auto cleanup = [&](){ - OsEng.deinitialize(); - - // Clear function bindings to avoid crash after destroying the OpenSpace Engine - sgct::MessageHandler::instance()->setLogToCallback(false); - sgct::MessageHandler::instance()->setLogCallback(nullptr); - - LDEBUG("Destroying OpenSpaceEngine"); - openspace::OpenSpaceEngine::destroy(); - - LDEBUG("Destroying SGCT Engine"); - delete SgctEngine; - - -#ifdef OPENVR_SUPPORT - // Clean up OpenVR - sgct::SGCTOpenVR::shutdown(); -#endif - -#ifdef OPENSPACE_HAS_SPOUT - for (SpoutWindow& w : SpoutWindows) { - if (w.leftOrMain.handle) { - w.leftOrMain.handle->ReleaseReceiver(); - w.leftOrMain.handle->Release(); - } - if (w.right.handle) { - w.right.handle->ReleaseReceiver(); - w.right.handle->Release(); - } - } -#endif // OPENSPACE_HAS_SPOUT - }; - - bool initSuccess = SgctEngine->init(versionMapping[glVersion]); - - if (!initSuccess) { - LFATAL("Initializing failed"); - cleanup(); - return EXIT_FAILURE; - } - - // Main loop - LDEBUG("Starting rendering loop"); - SgctEngine->render(); - LDEBUG("Ending rendering loop"); - - cleanup(); - - // Exit program - exit(EXIT_SUCCESS); -} - -} // namespace - -int main(int argc, char** argv) { -#ifdef WIN32 - SetUnhandledExceptionFilter(generateMiniDump); -#endif // WIN32 - - // If we are working as a developer, we don't want to catch the exceptions in order to - // find the locations where the exceptions are raised. - // If we are not in developer mode, we want to catch and at least log the error before - // dying -#ifdef DEVELOPER_MODE - return main_main(argc, argv); -#else - // We wrap the actual main function in a try catch block so that we can get and print - // some additional information in case an exception is raised - try { - return main_main(argc, argv); - } - catch (const ghoul::RuntimeError& e) { - // Write out all of the information about the exception and flush the logs - LFATALC(e.component, e.message); - LogMgr.flushLogs(); - return EXIT_FAILURE; - } - catch (const ghoul::AssertionException& e) { - // We don't want to catch the assertion exception as we won't be able to add a - // breakpoint for debugging - LFATALC("Assertion failed", e.what()); - throw; - } catch (const std::exception& e) { - LFATALC("Exception", e.what()); - LogMgr.flushLogs(); - return EXIT_FAILURE; - } - catch (...) { - LFATALC("Exception", "Unknown exception"); - LogMgr.flushLogs(); - return EXIT_FAILURE; - } -#endif // DEVELOPER_MODE -} +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include +#include + +#include +#include +//#include + +#include + +#ifdef WIN32 + +#include + +#include +#include + +#include + +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4091) +#include +#pragma warning (pop) +#endif // _MSC_VER + +#endif // WIN32 + +#ifdef OPENVR_SUPPORT +#include +#endif // OPENVR_SUPPORT + +#ifdef OPENSPACE_HAS_SPOUT +#include "SpoutLibrary.h" +#endif // OPENSPACE_HAS_SPOUT + + +#define DEVELOPER_MODE + +namespace { + +const char* _loggerCat = "main"; +sgct::Engine* SgctEngine; + +const char* OpenVRTag = "OpenVR"; +const char* SpoutTag = "Spout"; + +#ifdef WIN32 + +LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) { + SYSTEMTIME stLocalTime; + GetLocalTime(&stLocalTime); + + + LFATAL("Printing Stack Trace that lead to the crash:"); + std::vector stackTrace = ghoul::stackTrace(); + for (const std::string& s : stackTrace) { + LINFO(s); + } + + std::string dumpFile = fmt::format( + "OpenSpace_{}_{}_{}-{}-{}-{}-{}-{}-{}--{}--{}.dmp", + openspace::OPENSPACE_VERSION_MAJOR, + openspace::OPENSPACE_VERSION_MINOR, + openspace::OPENSPACE_VERSION_PATCH, + stLocalTime.wYear, + stLocalTime.wMonth, + stLocalTime.wDay, + stLocalTime.wHour, + stLocalTime.wMinute, + stLocalTime.wSecond, + GetCurrentProcessId(), + GetCurrentThreadId() + ); + + LINFO("Creating dump file: " << dumpFile); + + HANDLE hDumpFile = CreateFile( + dumpFile.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, + 0, + CREATE_ALWAYS, + 0, + 0 + ); + + MINIDUMP_EXCEPTION_INFORMATION exceptionParameter; + exceptionParameter.ThreadId = GetCurrentThreadId(); + exceptionParameter.ExceptionPointers = exceptionPointers; + exceptionParameter.ClientPointers = TRUE; + + BOOL success = MiniDumpWriteDump( + GetCurrentProcess(), + GetCurrentProcessId(), + hDumpFile, + MiniDumpWithDataSegs, + &exceptionParameter, + nullptr, + nullptr + ); + + if (success) { + LINFO("Created successfully"); + } + else { + LERROR("Dumpfile created unsuccessfully"); + } + + return EXCEPTION_EXECUTE_HANDLER; +} + +#endif // WIN32 + +#ifdef OPENVR_SUPPORT +sgct::SGCTWindow* FirstOpenVRWindow = nullptr; +#endif + +#ifdef OPENSPACE_HAS_SPOUT +/** + * This struct stores all information about a single render window. Depending on the + * frame setup, each window can be mono or stereo, the information of which is stored in + * the \c leftOrMain and \c right members respectively. + */ +struct SpoutWindow { + struct SpoutData { + SPOUTHANDLE handle = nullptr; + bool initialized = false; + }; + + /// The left framebuffer (or main, if there is no stereo rendering) + SpoutData leftOrMain; + + /// The right framebuffer + SpoutData right; + + /// The window ID of this windows + size_t windowId = size_t(-1); +}; + +/// The list of all windows with spout senders +std::vector SpoutWindows; + +#endif // OPENSPACE_HAS_SPOUT + + + +std::pair supportedOpenGLVersion() { + // Just create a window in order to retrieve the available OpenGL version before we + // create the real window + glfwInit(); + + // On OS X we need to explicitly set the version and specify that we are using CORE + // profile to be able to use glGetIntegerv(GL_MAJOR_VERSION, &major) and + // glGetIntegerv(GL_MINOR_VERSION, &minor) explicitly setting to OGL 3.3 CORE works + // since all Mac's now support at least 3.3 +#ifdef __APPLE__ + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); +#endif + + glfwWindowHint(GLFW_VISIBLE, GL_FALSE); + + // By creating an offscreen window, the user will not know that we created this window + GLFWwindow* offscreen = glfwCreateWindow(128, 128, "", nullptr, nullptr); + glfwMakeContextCurrent(offscreen); + + // Get the OpenGL version + int major, minor; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + + // And get rid of the window again + glfwDestroyWindow(offscreen); + glfwWindowHint(GLFW_VISIBLE, GL_TRUE); + + return { major, minor }; +} + +void mainInitFunc() { + LTRACE("main::mainInitFunc(begin)"); + + LDEBUG("Initializing OpenSpace Engine started"); + OsEng.initialize(); + LDEBUG("Initializing OpenSpace Engine finished"); + + LDEBUG("Initializing OpenGL in OpenSpace Engine started"); + OsEng.initializeGL(); + LDEBUG("Initializing OpenGL in OpenSpace Engine finished"); + + // Find if we have at least one OpenVR window + // Save reference to first OpenVR window, which is the one we will copy to the HMD. + for (size_t i = 0; i < SgctEngine->getNumberOfWindows(); ++i) { + if (SgctEngine->getWindowPtr(i)->checkIfTagExists(OpenVRTag)) { +#ifdef OPENVR_SUPPORT + FirstOpenVRWindow = SgctEngine->getWindowPtr(i); + + // If we have an OpenVRWindow, initialize OpenVR. + sgct::SGCTOpenVR::initialize( + SgctEngine->getNearClippingPlane(), SgctEngine->getFarClippingPlane() + ); +#else + LWARNING( + "OpenVR was requested, but OpenSpace was compiled without VR support." + ); +#endif + + break; + } + } + + // Set the clear color for all non-linear projection viewports + // @CLEANUP: Why is this necessary? We can set the clear color in the configuration + // files --- abock + const size_t nWindows = SgctEngine->getNumberOfWindows(); + for (size_t i = 0; i < nWindows; ++i) { + sgct::SGCTWindow* w = SgctEngine->getWindowPtr(i); + const size_t nViewports = w->getNumberOfViewports(); + for (size_t j = 0; j < nViewports; ++j) { + sgct_core::Viewport* v = w->getViewport(j); + ghoul_assert(v != nullptr, "Number of reported viewports was incorrect"); + sgct_core::NonLinearProjection* p = v->getNonLinearProjectionPtr(); + if (p) { + p->setClearColor(glm::vec4(0.f, 0.f, 0.f, 1.f)); + } + } + } + + for (size_t i = 0; i < nWindows; ++i) { + const sgct::SGCTWindow* windowPtr = SgctEngine->getWindowPtr(i); + + if (!windowPtr->checkIfTagExists(SpoutTag)) { + continue; + } + +#ifdef OPENSPACE_HAS_SPOUT + SpoutWindow w; + + w.windowId = i; + + const sgct::SGCTWindow::StereoMode sm = windowPtr->getStereoMode(); + const bool hasStereo = + (sm != sgct::SGCTWindow::No_Stereo) && + (sm < sgct::SGCTWindow::Side_By_Side_Stereo); + + if (hasStereo) { + SpoutWindow::SpoutData& left = w.leftOrMain; + left.handle = GetSpout(); + left.initialized = left.handle->CreateSender( + (windowPtr->getName() + "_left").c_str(), + windowPtr->getXFramebufferResolution(), + windowPtr->getYFramebufferResolution() + ); + + SpoutWindow::SpoutData& right = w.right; + right.handle = GetSpout(); + right.initialized = right.handle->CreateSender( + (windowPtr->getName() + "_right").c_str(), + windowPtr->getXFramebufferResolution(), + windowPtr->getYFramebufferResolution() + ); + } + else { + SpoutWindow::SpoutData& main = w.leftOrMain; + main.handle = GetSpout(); + main.initialized = main.handle->CreateSender( + windowPtr->getName().c_str(), + windowPtr->getXFramebufferResolution(), + windowPtr->getYFramebufferResolution() + ); + } + + SpoutWindows.push_back(std::move(w)); +#else + LWARNING( + "Spout was requested, but OpenSpace was compiled without Spout support." + ); + +#endif // OPENSPACE_HAS_SPOUT + } + LTRACE("main::mainInitFunc(end)"); +} + +void mainPreSyncFunc() { + LTRACE("main::mainPreSyncFunc(begin)"); + OsEng.setRunTime(sgct::Engine::getTime()); + OsEng.preSynchronization(); + LTRACE("main::mainPreSyncFunc(end)"); +} + +void mainPostSyncPreDrawFunc() { + LTRACE("main::postSynchronizationPreDraw(begin)"); + OsEng.postSynchronizationPreDraw(); + +#ifdef OPENVR_SUPPORT + if (FirstOpenVRWindow) { + // Update pose matrices for all tracked OpenVR devices once per frame + sgct::SGCTOpenVR::updatePoses(); + } +#endif // OPENVR_SUPPORT + + LTRACE("main::postSynchronizationPreDraw(end)"); +} + +void mainRenderFunc() { + LTRACE("main::mainRenderFunc(begin)"); + + glm::mat4 viewMatrix = + SgctEngine->getCurrentViewMatrix() * + // User matrix + glm::translate( + glm::mat4(1.f), + SgctEngine->getDefaultUserPtr()->getPos() + ) + ; + + glm::mat4 projectionMatrix = SgctEngine->getCurrentProjectionMatrix(); +#ifdef OPENVR_SUPPORT + bool currentWindowIsHMD = FirstOpenVRWindow == SgctEngine->getCurrentWindowPtr(); + if (sgct::SGCTOpenVR::isHMDActive() && currentWindowIsHMD) { + projectionMatrix = sgct::SGCTOpenVR::getHMDCurrentViewProjectionMatrix( + SgctEngine->getCurrentFrustumMode() + ); + } +#endif + + OsEng.render( + SgctEngine->getModelMatrix(), + viewMatrix, + projectionMatrix + ); + LTRACE("main::mainRenderFunc(end)"); +} + +void mainPostDrawFunc() { + LTRACE("main::mainPostDrawFunc(begin)"); + +#ifdef OPENVR_SUPPORT + if (FirstOpenVRWindow) { + // Copy the first OpenVR window to the HMD + sgct::SGCTOpenVR::copyWindowToHMD(FirstOpenVRWindow); + } +#endif // OPENVR_SUPPORT + + OsEng.postDraw(); + +#ifdef OPENSPACE_HAS_SPOUT + for (const SpoutWindow& w : SpoutWindows) { + sgct::SGCTWindow* window = SgctEngine->getWindowPtr(w.windowId); + if (w.leftOrMain.initialized) { + GLuint texId = window->getFrameBufferTexture(sgct::Engine::LeftEye); + glBindTexture(GL_TEXTURE_2D, texId); + w.leftOrMain.handle->SendTexture( + texId, + GL_TEXTURE_2D, + window->getXFramebufferResolution(), + window->getYFramebufferResolution() + ); + } + + if (w.right.initialized) { + GLuint texId = window->getFrameBufferTexture(sgct::Engine::RightEye); + glBindTexture(GL_TEXTURE_2D, texId); + w.right.handle->SendTexture( + texId, + GL_TEXTURE_2D, + window->getXFramebufferResolution(), + window->getYFramebufferResolution() + ); + } + } + glBindTexture(GL_TEXTURE_2D, 0); +#endif // OPENSPACE_HAS_SPOUT + + LTRACE("main::mainPostDrawFunc(end)"); +} + +void mainExternalControlCallback(const char* receivedChars, int size) { + LTRACE("main::mainExternalControlCallback(begin)"); + if (SgctEngine->isMaster()) { + OsEng.externalControlCallback(receivedChars, size, 0); + } + LTRACE("main::mainExternalControlCallback(end)"); +} + +void mainKeyboardCallback(int key, int, int action, int mods) { + LTRACE("main::mainKeyboardCallback(begin)"); + if (SgctEngine->isMaster()) { + OsEng.keyboardCallback( + openspace::Key(key), + openspace::KeyModifier(mods), + openspace::KeyAction(action) + ); + } + LTRACE("main::mainKeyboardCallback(begin)"); +} + +void mainMouseButtonCallback(int key, int action) { + LTRACE("main::mainMouseButtonCallback(begin)"); + if (SgctEngine->isMaster()) { + OsEng.mouseButtonCallback( + openspace::MouseButton(key), + openspace::MouseAction(action) + ); + } + LTRACE("main::mainMouseButtonCallback(end)"); +} + +void mainMousePosCallback(double x, double y) { + if (SgctEngine->isMaster()) { + OsEng.mousePositionCallback(x, y); + } +} + +void mainMouseScrollCallback(double, double posY) { + LTRACE("main::mainMouseScrollCallback(begin"); + if (SgctEngine->isMaster()) { + OsEng.mouseScrollWheelCallback(posY); + } + LTRACE("main::mainMouseScrollCallback(end)"); +} + +void mainCharCallback(unsigned int codepoint, int mods) { + if (SgctEngine->isMaster()) { + OsEng.charCallback(codepoint, openspace::KeyModifier(mods)); + } +} + +void mainEncodeFun() { + LTRACE("main::mainEncodeFun(begin)"); + OsEng.encode(); + LTRACE("main::mainEncodeFun(end)"); +} + +void mainDecodeFun() { + LTRACE("main::mainDecodeFun(begin)"); + OsEng.decode(); + LTRACE("main::mainDecodeFun(end)"); +} + +void mainLogCallback(const char* msg) { + std::string message = msg; + if (message.empty() || message == ".") { + // We don't want the empty '.' message that SGCT sends while it is waiting for + // connections from other network nodes + return; + } + // Remove the trailing \n that is passed along + LINFOC("SGCT", message.substr(0, message.size() - 1)); +} + +int main_main(int argc, char** argv) { + std::pair glVersion = supportedOpenGLVersion(); + + // Create the OpenSpace engine and get arguments for the SGCT engine + // @CLEANUP: Replace the return valua with throwing an exception --abock + std::vector sgctArguments; + bool requestQuit = false; + openspace::OpenSpaceEngine::create( + argc, argv, + std::make_unique(), + sgctArguments, + requestQuit + ); + + if (requestQuit) { + return EXIT_SUCCESS; + } + + LINFO("Detected OpenGL version: " << glVersion.first << "." << glVersion.second); + + // Create sgct engine c arguments + int newArgc = static_cast(sgctArguments.size()); + + char** newArgv = new char*[newArgc]; + for (int i = 0; i < newArgc; ++i) { + newArgv[i] = const_cast(sgctArguments.at(i).c_str()); + } + + // Need to set this before the creation of the sgct::Engine + sgct::MessageHandler::instance()->setLogToConsole(false); + sgct::MessageHandler::instance()->setShowTime(false); + sgct::MessageHandler::instance()->setLogToCallback(true); + sgct::MessageHandler::instance()->setLogCallback(mainLogCallback); + +#ifdef __APPLE__ + glfwWindowHint(GLFW_STENCIL_BITS, 8); +#endif + + LDEBUG("Creating SGCT Engine"); + SgctEngine = new sgct::Engine(newArgc, newArgv); + + // Deallocate sgct c arguments + delete[] newArgv; + + // Bind functions + SgctEngine->setInitOGLFunction(mainInitFunc); + SgctEngine->setPreSyncFunction(mainPreSyncFunc); + SgctEngine->setPostSyncPreDrawFunction(mainPostSyncPreDrawFunc); + SgctEngine->setDrawFunction(mainRenderFunc); + SgctEngine->setPostDrawFunction(mainPostDrawFunc); + SgctEngine->setKeyboardCallbackFunction(mainKeyboardCallback); + SgctEngine->setMouseButtonCallbackFunction(mainMouseButtonCallback); + SgctEngine->setMousePosCallbackFunction(mainMousePosCallback); + SgctEngine->setMouseScrollCallbackFunction(mainMouseScrollCallback); + SgctEngine->setExternalControlCallback(mainExternalControlCallback); + SgctEngine->setCharCallbackFunction(mainCharCallback); + + // Disable the immediate exit of the application when the ESC key is pressed + SgctEngine->setExitKey(SGCT_KEY_UNKNOWN); + + sgct::MessageHandler::instance()->setNotifyLevel(sgct::MessageHandler::NOTIFY_ALL); + + // Set encode and decode functions + // NOTE: starts synchronizing before init functions + sgct::SharedData::instance()->setEncodeFunction(mainEncodeFun); + sgct::SharedData::instance()->setDecodeFunction(mainDecodeFun); + + // Try to open a window + LDEBUG("Initialize SGCT Engine"); + std::map, sgct::Engine::RunMode> versionMapping = { + { { 3, 3 }, sgct::Engine::RunMode::OpenGL_3_3_Core_Profile }, + { { 4, 0 }, sgct::Engine::RunMode::OpenGL_4_0_Core_Profile }, + { { 4, 1 }, sgct::Engine::RunMode::OpenGL_4_1_Core_Profile }, + { { 4, 2 }, sgct::Engine::RunMode::OpenGL_4_2_Core_Profile }, + { { 4, 3 }, sgct::Engine::RunMode::OpenGL_4_3_Core_Profile }, + { { 4, 4 }, sgct::Engine::RunMode::OpenGL_4_4_Core_Profile }, + { { 4, 5 }, sgct::Engine::RunMode::OpenGL_4_5_Core_Profile } + }; + ghoul_assert( + versionMapping.find(glVersion) != versionMapping.end(), + "Unknown OpenGL version. Missing statement in version mapping map" + ); + + auto cleanup = [&](){ + OsEng.deinitialize(); + + // Clear function bindings to avoid crash after destroying the OpenSpace Engine + sgct::MessageHandler::instance()->setLogToCallback(false); + sgct::MessageHandler::instance()->setLogCallback(nullptr); + + LDEBUG("Destroying OpenSpaceEngine"); + openspace::OpenSpaceEngine::destroy(); + + LDEBUG("Destroying SGCT Engine"); + delete SgctEngine; + + +#ifdef OPENVR_SUPPORT + // Clean up OpenVR + sgct::SGCTOpenVR::shutdown(); +#endif + +#ifdef OPENSPACE_HAS_SPOUT + for (SpoutWindow& w : SpoutWindows) { + if (w.leftOrMain.handle) { + w.leftOrMain.handle->ReleaseReceiver(); + w.leftOrMain.handle->Release(); + } + if (w.right.handle) { + w.right.handle->ReleaseReceiver(); + w.right.handle->Release(); + } + } +#endif // OPENSPACE_HAS_SPOUT + }; + + bool initSuccess = SgctEngine->init(versionMapping[glVersion]); + + if (!initSuccess) { + LFATAL("Initializing failed"); + cleanup(); + return EXIT_FAILURE; + } + + // Main loop + LDEBUG("Starting rendering loop"); + SgctEngine->render(); + LDEBUG("Ending rendering loop"); + + cleanup(); + + // Exit program + exit(EXIT_SUCCESS); +} + +} // namespace + +int main(int argc, char** argv) { +#ifdef WIN32 + SetUnhandledExceptionFilter(generateMiniDump); +#endif // WIN32 + + // If we are working as a developer, we don't want to catch the exceptions in order to + // find the locations where the exceptions are raised. + // If we are not in developer mode, we want to catch and at least log the error before + // dying +#ifdef DEVELOPER_MODE + return main_main(argc, argv); +#else + // We wrap the actual main function in a try catch block so that we can get and print + // some additional information in case an exception is raised + try { + return main_main(argc, argv); + } + catch (const ghoul::RuntimeError& e) { + // Write out all of the information about the exception and flush the logs + LFATALC(e.component, e.message); + LogMgr.flushLogs(); + return EXIT_FAILURE; + } + catch (const ghoul::AssertionException& e) { + // We don't want to catch the assertion exception as we won't be able to add a + // breakpoint for debugging + LFATALC("Assertion failed", e.what()); + throw; + } catch (const std::exception& e) { + LFATALC("Exception", e.what()); + LogMgr.flushLogs(); + return EXIT_FAILURE; + } + catch (...) { + LFATALC("Exception", "Unknown exception"); + LogMgr.flushLogs(); + return EXIT_FAILURE; + } +#endif // DEVELOPER_MODE +} diff --git a/ext/ghoul b/ext/ghoul index f852572b77..5b75ba44ca 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit f852572b77742d4fa6c78e73b6f5470633509c8f +Subproject commit 5b75ba44caec9ee798f7a3390dbdcb4870398886 diff --git a/modules/globebrowsing/other/pixelbuffer.cpp b/modules/globebrowsing/other/pixelbuffer.cpp index 22b8264a48..1882419d7b 100644 --- a/modules/globebrowsing/other/pixelbuffer.cpp +++ b/modules/globebrowsing/other/pixelbuffer.cpp @@ -1,84 +1,84 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include - -namespace { - const char* _loggerCat = "PixelBuffer"; -}; - -using namespace openspace::globebrowsing; - -PixelBuffer::PixelBuffer(size_t numBytes, Usage usage) - : _numBytes(numBytes) - , _usage(usage) - , _isMapped(false) -{ - glGenBuffers(1, &_id); - bind(); - glBufferData(GL_PIXEL_UNPACK_BUFFER, _numBytes, 0, static_cast(_usage)); - unbind(); -} - -PixelBuffer::~PixelBuffer() { - glDeleteBuffers(1, &_id); -} - -void* PixelBuffer::mapBuffer(Access access) { - void* dataPtr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast(access)); - _isMapped = dataPtr ? true : false; - return dataPtr; -} - -void* PixelBuffer::mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access) { - void* dataPtr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, offset, length, access); - _isMapped = dataPtr ? true : false; - return dataPtr; -} - -bool PixelBuffer::unMapBuffer() { - GLboolean success = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - if (!success) { - LERROR("Unable to unmap pixel buffer, data may be corrupt!"); - } - _isMapped = false; - return success == GL_TRUE; -} - -void PixelBuffer::bind() { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _id); -} - -void PixelBuffer::unbind() { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); -} - -bool PixelBuffer::isMapped() const { - return _isMapped; -} - -PixelBuffer::operator GLuint() const { - return _id; -} +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +namespace { + const char* _loggerCat = "PixelBuffer"; +}; + +using namespace openspace::globebrowsing; + +PixelBuffer::PixelBuffer(size_t numBytes, Usage usage) + : _numBytes(numBytes) + , _usage(usage) + , _isMapped(false) +{ + glGenBuffers(1, &_id); + bind(); + glBufferData(GL_PIXEL_UNPACK_BUFFER, _numBytes, 0, static_cast(_usage)); + unbind(); +} + +PixelBuffer::~PixelBuffer() { + glDeleteBuffers(1, &_id); +} + +void* PixelBuffer::mapBuffer(Access access) { + void* dataPtr = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, static_cast(access)); + _isMapped = dataPtr ? true : false; + return dataPtr; +} + +void* PixelBuffer::mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access) { + void* dataPtr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, offset, length, access); + _isMapped = dataPtr ? true : false; + return dataPtr; +} + +bool PixelBuffer::unMapBuffer() { + GLboolean success = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + if (!success) { + LERROR("Unable to unmap pixel buffer, data may be corrupt!"); + } + _isMapped = false; + return success == GL_TRUE; +} + +void PixelBuffer::bind() { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _id); +} + +void PixelBuffer::unbind() { + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); +} + +bool PixelBuffer::isMapped() const { + return _isMapped; +} + +PixelBuffer::operator GLuint() const { + return _id; +} diff --git a/modules/globebrowsing/other/pixelbuffer.h b/modules/globebrowsing/other/pixelbuffer.h index 1f9ee4918e..11e8f97811 100644 --- a/modules/globebrowsing/other/pixelbuffer.h +++ b/modules/globebrowsing/other/pixelbuffer.h @@ -1,140 +1,140 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ - -#include - -namespace openspace { -namespace globebrowsing { - -/** - * Handles an OpenGL pixel buffer which contains data allocated on the GPU. A simple - * class that wraps the standard functionality of OpenGL pixel buffer objects. Once - * the PixelBuffer is created, data is allocated on the GPU. When mapping data to a - * address pointer, the user needs to ensure the data is unmapped before the data can - * be used on the GPU / CPU depending on Usage. - */ -class PixelBuffer -{ -public: - /** - * All kinds of usage for pixel buffer objects as defined by the OpenGL standard. - * See: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml - */ - enum class Usage : std::underlying_type_t { - StreamDraw = static_cast>(GL_STREAM_DRAW), - StreamRead = static_cast>(GL_STREAM_READ), - StreamCopy = static_cast>(GL_STREAM_COPY), - StaticDraw = static_cast>(GL_STATIC_DRAW), - StaticRead = static_cast>(GL_STATIC_READ), - StaticCopy = static_cast>(GL_STATIC_COPY), - DynamicDraw = static_cast>(GL_DYNAMIC_DRAW), - DynamicRead = static_cast>(GL_DYNAMIC_READ), - DynamicCopy = static_cast>(GL_DYNAMIC_COPY) - }; - - /** - * Access hints for OpenGL buffer mapping - * See: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glMapBuffer.xml - */ - enum class Access : std::underlying_type_t { - ReadOnly = static_cast>(GL_READ_ONLY), - WriteOnly = static_cast>(GL_WRITE_ONLY), - ReadWrite = static_cast>(GL_READ_WRITE) - }; - - /** - * Allocates numBytes bytes on the GPU and creates an ID for the pixel - * buffer object. - * \param numBytes is the number of bytes to be allocated on GPU memory - * \param usage is the Usage for the pixel buffer - */ - PixelBuffer(size_t numBytes, Usage usage); - - /** - * calls glDeleteBuffers(). - */ - ~PixelBuffer(); - - /** - * Maps an address pointer to GPU direct memory access. The user must make sure the - * buffer is bound before calling this function. - * \param access is the access to which can be any of GL_READ_ONLY, - * GL_WRITE_ONLY, or GL_READ_WRITE - * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping - * failed - */ - void* mapBuffer(Access access); - - /** - * Maps an address pointer to GPU direct memory access. Gives access to a range of - * the buffer. The user must make sure the buffer is bound before calling this - * function. - * \param offet is the number of bytes to the first address to get in the buffer - * \param length is the number of bytes to access in the buffer - * \param access is a bitfield describing the access as described in: - * https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glMapBufferRange.xhtml - * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping - * failed - */ - void* mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access); - - /** - * Maps the default buffer and makes the data available on the GPU - */ - bool unMapBuffer(); - - /** - * Calls glBindBuffer() - */ - void bind(); - - /** - * Calls glBindBuffer() with argument 0 to unmap any pixel buffer - */ - void unbind(); - - /** - * \returns true of the buffer is mapped, otherwise false - */ - bool isMapped() const; - - /** - * \returns the OpenGL id of the pixel buffer object - */ - operator GLuint() const; - -private: - GLuint _id; - const size_t _numBytes; - const Usage _usage; - bool _isMapped; -}; - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ + +#include + +namespace openspace { +namespace globebrowsing { + +/** + * Handles an OpenGL pixel buffer which contains data allocated on the GPU. A simple + * class that wraps the standard functionality of OpenGL pixel buffer objects. Once + * the PixelBuffer is created, data is allocated on the GPU. When mapping data to a + * address pointer, the user needs to ensure the data is unmapped before the data can + * be used on the GPU / CPU depending on Usage. + */ +class PixelBuffer +{ +public: + /** + * All kinds of usage for pixel buffer objects as defined by the OpenGL standard. + * See: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml + */ + enum class Usage : std::underlying_type_t { + StreamDraw = static_cast>(GL_STREAM_DRAW), + StreamRead = static_cast>(GL_STREAM_READ), + StreamCopy = static_cast>(GL_STREAM_COPY), + StaticDraw = static_cast>(GL_STATIC_DRAW), + StaticRead = static_cast>(GL_STATIC_READ), + StaticCopy = static_cast>(GL_STATIC_COPY), + DynamicDraw = static_cast>(GL_DYNAMIC_DRAW), + DynamicRead = static_cast>(GL_DYNAMIC_READ), + DynamicCopy = static_cast>(GL_DYNAMIC_COPY) + }; + + /** + * Access hints for OpenGL buffer mapping + * See: https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glMapBuffer.xml + */ + enum class Access : std::underlying_type_t { + ReadOnly = static_cast>(GL_READ_ONLY), + WriteOnly = static_cast>(GL_WRITE_ONLY), + ReadWrite = static_cast>(GL_READ_WRITE) + }; + + /** + * Allocates numBytes bytes on the GPU and creates an ID for the pixel + * buffer object. + * \param numBytes is the number of bytes to be allocated on GPU memory + * \param usage is the Usage for the pixel buffer + */ + PixelBuffer(size_t numBytes, Usage usage); + + /** + * calls glDeleteBuffers(). + */ + ~PixelBuffer(); + + /** + * Maps an address pointer to GPU direct memory access. The user must make sure the + * buffer is bound before calling this function. + * \param access is the access to which can be any of GL_READ_ONLY, + * GL_WRITE_ONLY, or GL_READ_WRITE + * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping + * failed + */ + void* mapBuffer(Access access); + + /** + * Maps an address pointer to GPU direct memory access. Gives access to a range of + * the buffer. The user must make sure the buffer is bound before calling this + * function. + * \param offet is the number of bytes to the first address to get in the buffer + * \param length is the number of bytes to access in the buffer + * \param access is a bitfield describing the access as described in: + * https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glMapBufferRange.xhtml + * \returns the DMA address to the mapped buffer. Returns nullptr if the mapping + * failed + */ + void* mapBufferRange(GLintptr offset, GLsizeiptr length, BufferAccessMask access); + + /** + * Maps the default buffer and makes the data available on the GPU + */ + bool unMapBuffer(); + + /** + * Calls glBindBuffer() + */ + void bind(); + + /** + * Calls glBindBuffer() with argument 0 to unmap any pixel buffer + */ + void unbind(); + + /** + * \returns true of the buffer is mapped, otherwise false + */ + bool isMapped() const; + + /** + * \returns the OpenGL id of the pixel buffer object + */ + operator GLuint() const; + +private: + GLuint _id; + const size_t _numBytes; + const Usage _usage; + bool _isMapped; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER___H__ diff --git a/modules/globebrowsing/other/pixelbuffercontainer.h b/modules/globebrowsing/other/pixelbuffercontainer.h index f1fdcfb9aa..8dc0aa2dc6 100644 --- a/modules/globebrowsing/other/pixelbuffercontainer.h +++ b/modules/globebrowsing/other/pixelbuffercontainer.h @@ -1,115 +1,115 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ - -#include - -#include - -namespace openspace { -namespace globebrowsing { - -/** - * Templated class which owns one or many PixelBuffers. The - * KeyType is used to map a pixel buffer but only if it is not already - * mapped. - */ -template -class PixelBufferContainer -{ -public: - /** - * Creates numPixelBuffers pixel buffer objects, each with numBytesPerBuffer bytes - * allocated on the GPU. - * \param numBytesPerBuffer is the number of bytes per pixel buffer. All pixel - * buffers within a PixelBufferContainer have the same number of bytes - * \param usage is the Usage as described by PixelBuffer - * \param numPixelBuffers is the number of pixel buffers to create for this container. - * If numPixelBuffers is omitted, no pixel buffers are created. - */ - PixelBufferContainer(size_t numBytesPerBuffer, - globebrowsing::PixelBuffer::Usage usage, size_t numPixelBuffers = 0); - ~PixelBufferContainer() = default; - - /** - * Finds a Pixel buffer and maps it if it is available. - * \param key is the identifier for the pixel buffer which can be used later when - * unmapping the mapped pixel buffer. - * \param access is the access as described by PixelBuffer - * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr - * is returned. The mapping can fail if the buffer identified with key - * is already mapped or if something else failed. - */ - void* mapBuffer(KeyType key, PixelBuffer::Access access); - - /** - * Finds a Pixel buffer and maps a range of it if it is available. - * \param key is the identifier for the pixel buffer which can be used later when - * unmapping the mapped pixel buffer. - * \param offet is the number of bytes to the first address to get in the buffer - * \param length is the number of bytes to access in the buffer - * \param access is the access as described by PixelBuffer - * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr - * is returned. The mapping can fail if the buffer identified with key - * is already mapped or if something else failed. - */ - void* mapBufferRange(KeyType key, GLintptr offset, GLsizeiptr length, - BufferAccessMask access); - - /** - * Unmaps all buffers in the PixelBufferContainer. - * \returns true if the unmapping succeeded, otherwise false. - */ - bool resetMappedBuffers(); - - /** - * Unmaps a buffer that has previously been mapped. This buffer is identified using - * key. - * \param key is the identifier of the mapped buffer. - * \returns true if the unmapping succeeded, otherwise false. - */ - bool unMapBuffer(KeyType key); - - /** - * \returns the GLuint id of a pixel buffer identified by key - * if it currently is mapped. - */ - GLuint idOfMappedBuffer(KeyType key); -private: - const globebrowsing::PixelBuffer::Usage _usage; - - std::vector> _pixelBuffers; - - // Maps from KeyType to index of mapped buffers - std::map _indexMap; -}; - -} // namespace globebrowsing -} // namespace openspace - -#include "pixelbuffercontainer.inl" - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ + +#include + +#include + +namespace openspace { +namespace globebrowsing { + +/** + * Templated class which owns one or many PixelBuffers. The + * KeyType is used to map a pixel buffer but only if it is not already + * mapped. + */ +template +class PixelBufferContainer +{ +public: + /** + * Creates numPixelBuffers pixel buffer objects, each with numBytesPerBuffer bytes + * allocated on the GPU. + * \param numBytesPerBuffer is the number of bytes per pixel buffer. All pixel + * buffers within a PixelBufferContainer have the same number of bytes + * \param usage is the Usage as described by PixelBuffer + * \param numPixelBuffers is the number of pixel buffers to create for this container. + * If numPixelBuffers is omitted, no pixel buffers are created. + */ + PixelBufferContainer(size_t numBytesPerBuffer, + globebrowsing::PixelBuffer::Usage usage, size_t numPixelBuffers = 0); + ~PixelBufferContainer() = default; + + /** + * Finds a Pixel buffer and maps it if it is available. + * \param key is the identifier for the pixel buffer which can be used later when + * unmapping the mapped pixel buffer. + * \param access is the access as described by PixelBuffer + * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr + * is returned. The mapping can fail if the buffer identified with key + * is already mapped or if something else failed. + */ + void* mapBuffer(KeyType key, PixelBuffer::Access access); + + /** + * Finds a Pixel buffer and maps a range of it if it is available. + * \param key is the identifier for the pixel buffer which can be used later when + * unmapping the mapped pixel buffer. + * \param offet is the number of bytes to the first address to get in the buffer + * \param length is the number of bytes to access in the buffer + * \param access is the access as described by PixelBuffer + * \returns an address pointer to DMA if the mapping succeeded. Otherwise a nullptr + * is returned. The mapping can fail if the buffer identified with key + * is already mapped or if something else failed. + */ + void* mapBufferRange(KeyType key, GLintptr offset, GLsizeiptr length, + BufferAccessMask access); + + /** + * Unmaps all buffers in the PixelBufferContainer. + * \returns true if the unmapping succeeded, otherwise false. + */ + bool resetMappedBuffers(); + + /** + * Unmaps a buffer that has previously been mapped. This buffer is identified using + * key. + * \param key is the identifier of the mapped buffer. + * \returns true if the unmapping succeeded, otherwise false. + */ + bool unMapBuffer(KeyType key); + + /** + * \returns the GLuint id of a pixel buffer identified by key + * if it currently is mapped. + */ + GLuint idOfMappedBuffer(KeyType key); +private: + const globebrowsing::PixelBuffer::Usage _usage; + + std::vector> _pixelBuffers; + + // Maps from KeyType to index of mapped buffers + std::map _indexMap; +}; + +} // namespace globebrowsing +} // namespace openspace + +#include "pixelbuffercontainer.inl" + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PIXEL_BUFFER_CONTAINER___H__ diff --git a/modules/globebrowsing/other/pixelbuffercontainer.inl b/modules/globebrowsing/other/pixelbuffercontainer.inl index c1a4e4aaa2..e3a1433e0a 100644 --- a/modules/globebrowsing/other/pixelbuffercontainer.inl +++ b/modules/globebrowsing/other/pixelbuffercontainer.inl @@ -1,130 +1,130 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -namespace openspace { -namespace globebrowsing { - -template -PixelBufferContainer::PixelBufferContainer(size_t numBytesPerBuffer, - PixelBuffer::Usage usage, size_t numPixelBuffers) - : _usage(usage) -{ - for (size_t i = 0; i < numPixelBuffers; ++i) { - _pixelBuffers.push_back(std::make_unique(numBytesPerBuffer, _usage)); - } -} - -template -void* PixelBufferContainer::mapBuffer(KeyType key, PixelBuffer::Access access) { - typename std::map::const_iterator iter = _indexMap.find(key); - const bool notFoundAmongMappedBuffers = (iter == _indexMap.end()); - - if (!notFoundAmongMappedBuffers) { // This PBO is already mapped - ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); - return nullptr; - } - - // Find a pixel buffer that is unmapped - for (size_t i = 0; i < _pixelBuffers.size(); ++i) { - if (!_pixelBuffers[i]->isMapped()) { - _pixelBuffers[i]->bind(); - void* dataPtr = _pixelBuffers[i]->mapBuffer(access); - _pixelBuffers[i]->unbind(); - if (dataPtr) { // Success in mapping - // Add this index to the map of mapped pixel buffers - _indexMap.emplace(key, i); - return dataPtr; - } - } - } - return nullptr; -} - -template -void* PixelBufferContainer::mapBufferRange(KeyType key, GLintptr offset, - GLsizeiptr length, BufferAccessMask access) -{ - typename std::map::const_iterator iter = _indexMap.find(key); - bool notFoundAmongMappedBuffers = iter == _indexMap.end(); - - if (!notFoundAmongMappedBuffers) { // This PBO is already mapped - ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); - return nullptr; - } - - // Find a pixel buffer that is unmapped - for (int i = 0; i < _pixelBuffers.size(); ++i) { - bool bufferIsMapped = _pixelBuffers[i]->isMapped(); - if (!bufferIsMapped) { - _pixelBuffers[i]->bind(); - void* dataPtr = _pixelBuffers[i]->mapBufferRange(offset, length, access); - _pixelBuffers[i]->unbind(); - if (dataPtr) { // Success in mapping - _indexMap.emplace(key, i); - return dataPtr; - } - } - } - return nullptr; -} - -template -bool PixelBufferContainer::resetMappedBuffers() { - bool success = true; - for (auto iter = _indexMap.begin(); iter != _indexMap.end(); iter++) { - int index = iter->second; // Index where the mapped buffer is stored - _pixelBuffers[index]->bind(); - success &= _pixelBuffers[index]->unMapBuffer(); - _pixelBuffers[index]->unbind(); - _indexMap.erase(iter); // This key should no longer be among the mapped buffers - } - return success; -} - -template -bool PixelBufferContainer::unMapBuffer(KeyType key) { - bool success = false; - typename std::map::const_iterator iter = _indexMap.find(key); - if (iter != _indexMap.end()) { // Found a mapped pixel buffer - int index = iter->second; // Index where the mapped buffer is stored - _pixelBuffers[index]->bind(); - success = _pixelBuffers[index]->unMapBuffer(); - _pixelBuffers[index]->unbind(); - _indexMap.erase(iter); // This key should no longer be among the mapped buffers - } - return success; -} - -template -GLuint PixelBufferContainer::idOfMappedBuffer(KeyType key) { - typename std::map::const_iterator iter = _indexMap.find(key); - if (iter != _indexMap.end()) { // Found a mapped pixel buffer - int index = iter->second; // Index where the mapped buffer is stored - return *_pixelBuffers[index]; - } - return 0; -} - -} // namespace globebrowsing -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +namespace openspace { +namespace globebrowsing { + +template +PixelBufferContainer::PixelBufferContainer(size_t numBytesPerBuffer, + PixelBuffer::Usage usage, size_t numPixelBuffers) + : _usage(usage) +{ + for (size_t i = 0; i < numPixelBuffers; ++i) { + _pixelBuffers.push_back(std::make_unique(numBytesPerBuffer, _usage)); + } +} + +template +void* PixelBufferContainer::mapBuffer(KeyType key, PixelBuffer::Access access) { + typename std::map::const_iterator iter = _indexMap.find(key); + const bool notFoundAmongMappedBuffers = (iter == _indexMap.end()); + + if (!notFoundAmongMappedBuffers) { // This PBO is already mapped + ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); + return nullptr; + } + + // Find a pixel buffer that is unmapped + for (size_t i = 0; i < _pixelBuffers.size(); ++i) { + if (!_pixelBuffers[i]->isMapped()) { + _pixelBuffers[i]->bind(); + void* dataPtr = _pixelBuffers[i]->mapBuffer(access); + _pixelBuffers[i]->unbind(); + if (dataPtr) { // Success in mapping + // Add this index to the map of mapped pixel buffers + _indexMap.emplace(key, i); + return dataPtr; + } + } + } + return nullptr; +} + +template +void* PixelBufferContainer::mapBufferRange(KeyType key, GLintptr offset, + GLsizeiptr length, BufferAccessMask access) +{ + typename std::map::const_iterator iter = _indexMap.find(key); + bool notFoundAmongMappedBuffers = iter == _indexMap.end(); + + if (!notFoundAmongMappedBuffers) { // This PBO is already mapped + ghoul_assert(_pixelBuffers[iter->second], "Incorrect index map"); + return nullptr; + } + + // Find a pixel buffer that is unmapped + for (int i = 0; i < _pixelBuffers.size(); ++i) { + bool bufferIsMapped = _pixelBuffers[i]->isMapped(); + if (!bufferIsMapped) { + _pixelBuffers[i]->bind(); + void* dataPtr = _pixelBuffers[i]->mapBufferRange(offset, length, access); + _pixelBuffers[i]->unbind(); + if (dataPtr) { // Success in mapping + _indexMap.emplace(key, i); + return dataPtr; + } + } + } + return nullptr; +} + +template +bool PixelBufferContainer::resetMappedBuffers() { + bool success = true; + for (auto iter = _indexMap.begin(); iter != _indexMap.end(); iter++) { + int index = iter->second; // Index where the mapped buffer is stored + _pixelBuffers[index]->bind(); + success &= _pixelBuffers[index]->unMapBuffer(); + _pixelBuffers[index]->unbind(); + _indexMap.erase(iter); // This key should no longer be among the mapped buffers + } + return success; +} + +template +bool PixelBufferContainer::unMapBuffer(KeyType key) { + bool success = false; + typename std::map::const_iterator iter = _indexMap.find(key); + if (iter != _indexMap.end()) { // Found a mapped pixel buffer + int index = iter->second; // Index where the mapped buffer is stored + _pixelBuffers[index]->bind(); + success = _pixelBuffers[index]->unMapBuffer(); + _pixelBuffers[index]->unbind(); + _indexMap.erase(iter); // This key should no longer be among the mapped buffers + } + return success; +} + +template +GLuint PixelBufferContainer::idOfMappedBuffer(KeyType key) { + typename std::map::const_iterator iter = _indexMap.find(key); + if (iter != _indexMap.end()) { // Found a mapped pixel buffer + int index = iter->second; // Index where the mapped buffer is stored + return *_pixelBuffers[index]; + } + return 0; +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp index dfcf8d1d01..8bb8f7edc1 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp @@ -1,339 +1,339 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ -#ifdef GLOBEBROWSING_USE_GDAL - -#include - -#include -#include -#include -#include - -#include -#include // abspath -#include -#include -#include - -#include -#include -#include - -#include - -#include - -namespace { - const std::string _loggerCat = "GdalRawTileDataReader"; -} - -namespace openspace { -namespace globebrowsing { - -std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) { - return os << pr.start.x << ", " << pr.start.y << " with size " << pr.numPixels.x << - ", " << pr.numPixels.y; -} - -GdalRawTileDataReader::GdalRawTileDataReader(const std::string& filePath, - const TileTextureInitData& initData, - const std::string& baseDirectory, - RawTileDataReader::PerformPreprocessing preprocess) - : RawTileDataReader(initData, preprocess) - , _dataset(nullptr) -{ - _initDirectory = baseDirectory.empty() ? CPLGetCurrentDir() : baseDirectory; - _datasetFilePath = filePath; - - { // Aquire lock - std::lock_guard lockGuard(_datasetLock); - initialize(); - } -} - -GdalRawTileDataReader::~GdalRawTileDataReader() { - std::lock_guard lockGuard(_datasetLock); - if (_dataset != nullptr) { - GDALClose(_dataset); - _dataset = nullptr; - } -} - -void GdalRawTileDataReader::reset() { - std::lock_guard lockGuard(_datasetLock); - _cached._maxLevel = -1; - if (_dataset != nullptr) { - GDALClose(_dataset); - _dataset = nullptr; - } - initialize(); -} - -int GdalRawTileDataReader::maxChunkLevel() const { - return _cached._maxLevel; -} - -float GdalRawTileDataReader::noDataValueAsFloat() const { - return _gdalDatasetMetaDataCached.noDataValue; -} - -int GdalRawTileDataReader::rasterXSize() const { - return _gdalDatasetMetaDataCached.rasterXSize; -} - -int GdalRawTileDataReader::rasterYSize() const { - return _gdalDatasetMetaDataCached.rasterYSize; -} - -float GdalRawTileDataReader::depthOffset() const { - return _gdalDatasetMetaDataCached.offset; -} - -float GdalRawTileDataReader::depthScale() const { - return _gdalDatasetMetaDataCached.scale; -} - -std::array GdalRawTileDataReader::getGeoTransform() const { - return _gdalDatasetMetaDataCached.padfTransform; -} - -IODescription GdalRawTileDataReader::getIODescription(const TileIndex& tileIndex) const { - IODescription io; - io.read.region = highestResPixelRegion(tileIndex); - - // write region starts in origin - io.write.region.start = PixelRegion::PixelCoordinate(0, 0); - io.write.region.numPixels = PixelRegion::PixelCoordinate( - _initData.dimensionsWithoutPadding().x, _initData.dimensionsWithoutPadding().y); - - io.read.overview = 0; - io.read.fullRegion = fullPixelRegion(); - // For correct sampling in dataset, we need to pad the texture tile - - PixelRegion scaledPadding = padding; - double scale = - io.read.region.numPixels.x / static_cast(io.write.region.numPixels.x); - scaledPadding.numPixels *= scale; - scaledPadding.start *= scale; - - io.read.region.pad(scaledPadding); - io.write.region.pad(padding); - io.write.region.start = PixelRegion::PixelCoordinate(0, 0); - - io.write.bytesPerLine = _initData.bytesPerLine(); - io.write.totalNumBytes = _initData.totalNumBytes(); - - ghoul_assert(io.write.region.numPixels.x == io.write.region.numPixels.y, ""); - ghoul_assert(io.write.region.numPixels.x == _initData.dimensionsWithPadding().x, ""); - - return io; -} - -void GdalRawTileDataReader::initialize() { - _dataset = openGdalDataset(_datasetFilePath); - - // Assume all raster bands have the same data type - _gdalDatasetMetaDataCached.rasterCount = _dataset->GetRasterCount(); - _gdalDatasetMetaDataCached.scale = _dataset->GetRasterBand(1)->GetScale(); - _gdalDatasetMetaDataCached.offset = _dataset->GetRasterBand(1)->GetOffset(); - _gdalDatasetMetaDataCached.rasterXSize = _dataset->GetRasterXSize(); - _gdalDatasetMetaDataCached.rasterYSize = _dataset->GetRasterYSize(); - _gdalDatasetMetaDataCached.noDataValue = _dataset->GetRasterBand(1)->GetNoDataValue(); - _gdalDatasetMetaDataCached.dataType = tiledatatype::getGdalDataType(_initData.glType()); - - CPLErr err = _dataset->GetGeoTransform(&_gdalDatasetMetaDataCached.padfTransform[0]); - if (err == CE_Failure) { - _gdalDatasetMetaDataCached.padfTransform = RawTileDataReader::getGeoTransform(); - } - - _depthTransform = calculateTileDepthTransform(); - _cached._tileLevelDifference = - calculateTileLevelDifference(_initData.dimensionsWithoutPadding().x); - - int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); - _cached._maxLevel = -_cached._tileLevelDifference; - if (numOverviews > 0) { - _cached._maxLevel += numOverviews - 1; - } -} - -void GdalRawTileDataReader::readImageData( - IODescription& io, RawTile::ReadError& worstError, char* imageDataDest) const { - - // Only read the minimum number of rasters - int nRastersToRead = std::min(_gdalDatasetMetaDataCached.rasterCount, - static_cast(_initData.nRasters())); - - switch (_initData.ghoulTextureFormat()) { - case ghoul::opengl::Texture::Format::Red: - case ghoul::opengl::Texture::Format::RG: - case ghoul::opengl::Texture::Format::RGB: - case ghoul::opengl::Texture::Format::RGBA: { - // Read the data (each rasterband is a separate channel) - for (int i = 0; i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - - RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - break; - } - case ghoul::opengl::Texture::Format::BGR: { - // Read the data (each rasterband is a separate channel) - for (int i = 0; i < 3 && i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - - RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - break; - } - case ghoul::opengl::Texture::Format::BGRA: { - for (int i = 0; i < 3 && i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - - RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - if (nRastersToRead > 3) { // Alpha channel exists - // Last read is the alpha channel - char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); - RawTile::ReadError err = repeatedRasterRead(4, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - break; - } - default: { - ghoul_assert(false, "Texture format not supported for tiles"); - break; - } - } -} - -RawTile::ReadError GdalRawTileDataReader::rasterRead( - int rasterBand, const IODescription& io, char* dataDestination) const -{ - ghoul_assert(io.read.region.isInside(io.read.fullRegion), "write region of bounds!"); - ghoul_assert( - io.write.region.start.x >= 0 && io.write.region.start.y >= 0, - "Invalid write region" - ); - - PixelRegion::PixelCoordinate end = io.write.region.end(); - size_t largestIndex = - (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _initData.bytesPerPixel(); - ghoul_assert(largestIndex <= io.write.totalNumBytes, "Invalid write region"); - - char* dataDest = dataDestination; - - // GDAL reads pixels top to bottom, but we want our pixels bottom to top. - // Therefore, we increment the destination pointer to the last line on in the - // buffer, and the we specify in the rasterIO call that we want negative line - // spacing. Doing this compensates the flipped Y axis - dataDest += (io.write.totalNumBytes - io.write.bytesPerLine); - - // handle requested write region. Note -= since flipped y axis - dataDest -= io.write.region.start.y * io.write.bytesPerLine; - dataDest += io.write.region.start.x * _initData.bytesPerPixel(); - - GDALRasterBand* gdalRasterBand = _dataset->GetRasterBand(rasterBand); - CPLErr readError = CE_Failure; - readError = gdalRasterBand->RasterIO( - GF_Read, - io.read.region.start.x, // Begin read x - io.read.region.start.y, // Begin read y - io.read.region.numPixels.x, // width to read x - io.read.region.numPixels.y, // width to read y - dataDest, // Where to put data - io.write.region.numPixels.x, // width to write x in destination - io.write.region.numPixels.y, // width to write y in destination - _gdalDatasetMetaDataCached.dataType, // Type - _initData.bytesPerPixel(), // Pixel spacing - -io.write.bytesPerLine // Line spacing - ); - - // Convert error to RawTile::ReadError - RawTile::ReadError error; - switch (readError) { - case CE_None: error = RawTile::ReadError::None; break; - case CE_Debug: error = RawTile::ReadError::Debug; break; - case CE_Warning: error = RawTile::ReadError::Warning; break; - case CE_Failure: error = RawTile::ReadError::Failure; break; - case CE_Fatal: error = RawTile::ReadError::Fatal; break; - default: error = RawTile::ReadError::Failure; break; - } - return error; -} - -GDALDataset* GdalRawTileDataReader::openGdalDataset(const std::string& filePath) { - GDALDataset* dataset = static_cast( - GDALOpen(filePath.c_str(), GA_ReadOnly)); - if (!dataset) { - using namespace ghoul::filesystem; - std::string correctedPath = FileSystem::ref().pathByAppendingComponent( - _initDirectory, filePath - ); - - dataset = static_cast(GDALOpen(correctedPath.c_str(), GA_ReadOnly)); - if (!dataset) { - throw ghoul::RuntimeError("Failed to load dataset:\n" + filePath); - } - } - return dataset; -} - -int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) const { - GDALRasterBand* firstBand = _dataset->GetRasterBand(1); - GDALRasterBand* maxOverview; - int numOverviews = firstBand->GetOverviewCount(); - int sizeLevel0; - if (numOverviews <= 0) { // No overviews. Use first band. - maxOverview = firstBand; - } - else { // Pick the highest overview. - maxOverview = firstBand->GetOverview(numOverviews - 1); - } - sizeLevel0 = maxOverview->GetXSize(); - double diff = log2(minimumPixelSize) - log2(sizeLevel0); - return diff; -} - -} // namespace globebrowsing -} // namespace openspace - -#endif // GLOBEBROWSING_USE_GDAL +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ +#ifdef GLOBEBROWSING_USE_GDAL + +#include + +#include +#include +#include +#include + +#include +#include // abspath +#include +#include +#include + +#include +#include +#include + +#include + +#include + +namespace { + const std::string _loggerCat = "GdalRawTileDataReader"; +} + +namespace openspace { +namespace globebrowsing { + +std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) { + return os << pr.start.x << ", " << pr.start.y << " with size " << pr.numPixels.x << + ", " << pr.numPixels.y; +} + +GdalRawTileDataReader::GdalRawTileDataReader(const std::string& filePath, + const TileTextureInitData& initData, + const std::string& baseDirectory, + RawTileDataReader::PerformPreprocessing preprocess) + : RawTileDataReader(initData, preprocess) + , _dataset(nullptr) +{ + _initDirectory = baseDirectory.empty() ? CPLGetCurrentDir() : baseDirectory; + _datasetFilePath = filePath; + + { // Aquire lock + std::lock_guard lockGuard(_datasetLock); + initialize(); + } +} + +GdalRawTileDataReader::~GdalRawTileDataReader() { + std::lock_guard lockGuard(_datasetLock); + if (_dataset != nullptr) { + GDALClose(_dataset); + _dataset = nullptr; + } +} + +void GdalRawTileDataReader::reset() { + std::lock_guard lockGuard(_datasetLock); + _cached._maxLevel = -1; + if (_dataset != nullptr) { + GDALClose(_dataset); + _dataset = nullptr; + } + initialize(); +} + +int GdalRawTileDataReader::maxChunkLevel() const { + return _cached._maxLevel; +} + +float GdalRawTileDataReader::noDataValueAsFloat() const { + return _gdalDatasetMetaDataCached.noDataValue; +} + +int GdalRawTileDataReader::rasterXSize() const { + return _gdalDatasetMetaDataCached.rasterXSize; +} + +int GdalRawTileDataReader::rasterYSize() const { + return _gdalDatasetMetaDataCached.rasterYSize; +} + +float GdalRawTileDataReader::depthOffset() const { + return _gdalDatasetMetaDataCached.offset; +} + +float GdalRawTileDataReader::depthScale() const { + return _gdalDatasetMetaDataCached.scale; +} + +std::array GdalRawTileDataReader::getGeoTransform() const { + return _gdalDatasetMetaDataCached.padfTransform; +} + +IODescription GdalRawTileDataReader::getIODescription(const TileIndex& tileIndex) const { + IODescription io; + io.read.region = highestResPixelRegion(tileIndex); + + // write region starts in origin + io.write.region.start = PixelRegion::PixelCoordinate(0, 0); + io.write.region.numPixels = PixelRegion::PixelCoordinate( + _initData.dimensionsWithoutPadding().x, _initData.dimensionsWithoutPadding().y); + + io.read.overview = 0; + io.read.fullRegion = fullPixelRegion(); + // For correct sampling in dataset, we need to pad the texture tile + + PixelRegion scaledPadding = padding; + double scale = + io.read.region.numPixels.x / static_cast(io.write.region.numPixels.x); + scaledPadding.numPixels *= scale; + scaledPadding.start *= scale; + + io.read.region.pad(scaledPadding); + io.write.region.pad(padding); + io.write.region.start = PixelRegion::PixelCoordinate(0, 0); + + io.write.bytesPerLine = _initData.bytesPerLine(); + io.write.totalNumBytes = _initData.totalNumBytes(); + + ghoul_assert(io.write.region.numPixels.x == io.write.region.numPixels.y, ""); + ghoul_assert(io.write.region.numPixels.x == _initData.dimensionsWithPadding().x, ""); + + return io; +} + +void GdalRawTileDataReader::initialize() { + _dataset = openGdalDataset(_datasetFilePath); + + // Assume all raster bands have the same data type + _gdalDatasetMetaDataCached.rasterCount = _dataset->GetRasterCount(); + _gdalDatasetMetaDataCached.scale = _dataset->GetRasterBand(1)->GetScale(); + _gdalDatasetMetaDataCached.offset = _dataset->GetRasterBand(1)->GetOffset(); + _gdalDatasetMetaDataCached.rasterXSize = _dataset->GetRasterXSize(); + _gdalDatasetMetaDataCached.rasterYSize = _dataset->GetRasterYSize(); + _gdalDatasetMetaDataCached.noDataValue = _dataset->GetRasterBand(1)->GetNoDataValue(); + _gdalDatasetMetaDataCached.dataType = tiledatatype::getGdalDataType(_initData.glType()); + + CPLErr err = _dataset->GetGeoTransform(&_gdalDatasetMetaDataCached.padfTransform[0]); + if (err == CE_Failure) { + _gdalDatasetMetaDataCached.padfTransform = RawTileDataReader::getGeoTransform(); + } + + _depthTransform = calculateTileDepthTransform(); + _cached._tileLevelDifference = + calculateTileLevelDifference(_initData.dimensionsWithoutPadding().x); + + int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); + _cached._maxLevel = -_cached._tileLevelDifference; + if (numOverviews > 0) { + _cached._maxLevel += numOverviews - 1; + } +} + +void GdalRawTileDataReader::readImageData( + IODescription& io, RawTile::ReadError& worstError, char* imageDataDest) const { + + // Only read the minimum number of rasters + int nRastersToRead = std::min(_gdalDatasetMetaDataCached.rasterCount, + static_cast(_initData.nRasters())); + + switch (_initData.ghoulTextureFormat()) { + case ghoul::opengl::Texture::Format::Red: + case ghoul::opengl::Texture::Format::RG: + case ghoul::opengl::Texture::Format::RGB: + case ghoul::opengl::Texture::Format::RGBA: { + // Read the data (each rasterband is a separate channel) + for (int i = 0; i < nRastersToRead; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + break; + } + case ghoul::opengl::Texture::Format::BGR: { + // Read the data (each rasterband is a separate channel) + for (int i = 0; i < 3 && i < nRastersToRead; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + break; + } + case ghoul::opengl::Texture::Format::BGRA: { + for (int i = 0; i < 3 && i < nRastersToRead; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + if (nRastersToRead > 3) { // Alpha channel exists + // Last read is the alpha channel + char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); + RawTile::ReadError err = repeatedRasterRead(4, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + break; + } + default: { + ghoul_assert(false, "Texture format not supported for tiles"); + break; + } + } +} + +RawTile::ReadError GdalRawTileDataReader::rasterRead( + int rasterBand, const IODescription& io, char* dataDestination) const +{ + ghoul_assert(io.read.region.isInside(io.read.fullRegion), "write region of bounds!"); + ghoul_assert( + io.write.region.start.x >= 0 && io.write.region.start.y >= 0, + "Invalid write region" + ); + + PixelRegion::PixelCoordinate end = io.write.region.end(); + size_t largestIndex = + (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _initData.bytesPerPixel(); + ghoul_assert(largestIndex <= io.write.totalNumBytes, "Invalid write region"); + + char* dataDest = dataDestination; + + // GDAL reads pixels top to bottom, but we want our pixels bottom to top. + // Therefore, we increment the destination pointer to the last line on in the + // buffer, and the we specify in the rasterIO call that we want negative line + // spacing. Doing this compensates the flipped Y axis + dataDest += (io.write.totalNumBytes - io.write.bytesPerLine); + + // handle requested write region. Note -= since flipped y axis + dataDest -= io.write.region.start.y * io.write.bytesPerLine; + dataDest += io.write.region.start.x * _initData.bytesPerPixel(); + + GDALRasterBand* gdalRasterBand = _dataset->GetRasterBand(rasterBand); + CPLErr readError = CE_Failure; + readError = gdalRasterBand->RasterIO( + GF_Read, + io.read.region.start.x, // Begin read x + io.read.region.start.y, // Begin read y + io.read.region.numPixels.x, // width to read x + io.read.region.numPixels.y, // width to read y + dataDest, // Where to put data + io.write.region.numPixels.x, // width to write x in destination + io.write.region.numPixels.y, // width to write y in destination + _gdalDatasetMetaDataCached.dataType, // Type + _initData.bytesPerPixel(), // Pixel spacing + -io.write.bytesPerLine // Line spacing + ); + + // Convert error to RawTile::ReadError + RawTile::ReadError error; + switch (readError) { + case CE_None: error = RawTile::ReadError::None; break; + case CE_Debug: error = RawTile::ReadError::Debug; break; + case CE_Warning: error = RawTile::ReadError::Warning; break; + case CE_Failure: error = RawTile::ReadError::Failure; break; + case CE_Fatal: error = RawTile::ReadError::Fatal; break; + default: error = RawTile::ReadError::Failure; break; + } + return error; +} + +GDALDataset* GdalRawTileDataReader::openGdalDataset(const std::string& filePath) { + GDALDataset* dataset = static_cast( + GDALOpen(filePath.c_str(), GA_ReadOnly)); + if (!dataset) { + using namespace ghoul::filesystem; + std::string correctedPath = FileSystem::ref().pathByAppendingComponent( + _initDirectory, filePath + ); + + dataset = static_cast(GDALOpen(correctedPath.c_str(), GA_ReadOnly)); + if (!dataset) { + throw ghoul::RuntimeError("Failed to load dataset:\n" + filePath); + } + } + return dataset; +} + +int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) const { + GDALRasterBand* firstBand = _dataset->GetRasterBand(1); + GDALRasterBand* maxOverview; + int numOverviews = firstBand->GetOverviewCount(); + int sizeLevel0; + if (numOverviews <= 0) { // No overviews. Use first band. + maxOverview = firstBand; + } + else { // Pick the highest overview. + maxOverview = firstBand->GetOverview(numOverviews - 1); + } + sizeLevel0 = maxOverview->GetXSize(); + double diff = log2(minimumPixelSize) - log2(sizeLevel0); + return diff; +} + +} // namespace globebrowsing +} // namespace openspace + +#endif // GLOBEBROWSING_USE_GDAL diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp index 03a08c4ed0..ed8590a14a 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp @@ -1,614 +1,614 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#ifdef GLOBEBROWSING_USE_GDAL -#include -#include -#endif // GLOBEBROWSING_USE_GDAL - -#include -#include // abspath -#include - -#include - -#include - -#include -#include - -namespace { - const char* _loggerCat = "TileDataType"; -} - -namespace openspace { -namespace globebrowsing { -namespace tiledatatype { - -#ifdef GLOBEBROWSING_USE_GDAL - -float interpretFloat(GDALDataType gdalType, const char* src) { - switch (gdalType) { - case GDT_Byte: - return static_cast(*reinterpret_cast(src)); - case GDT_UInt16: - return static_cast(*reinterpret_cast(src)); - case GDT_Int16: - return static_cast(*reinterpret_cast(src)); - case GDT_UInt32: - return static_cast(*reinterpret_cast(src)); - case GDT_Int32: - return static_cast(*reinterpret_cast(src)); - case GDT_Float32: - return static_cast(*reinterpret_cast(src)); - case GDT_Float64: - return static_cast(*reinterpret_cast(src)); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -size_t numberOfBytes(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return sizeof(GLubyte); - case GDT_UInt16: - return sizeof(GLushort); - case GDT_Int16: - return sizeof(GLshort); - case GDT_UInt32: - return sizeof(GLuint); - case GDT_Int32: - return sizeof(GLint); - case GDT_Float32: - return sizeof(GLfloat); - case GDT_Float64: - return sizeof(GLdouble); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -size_t getMaximumValue(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return 1 << 8; - case GDT_UInt16: - return 1 << 16; - case GDT_Int16: - return 1 << 15; - case GDT_UInt32: - return size_t(1) << 32; - case GDT_Int32: - return 1 << 31; - default: - ghoul_assert(false, "Unknown data type"); - } -} - -TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType) { - TextureFormat format; - - switch (rasterCount) { - case 1: // Red - format.ghoulFormat = ghoul::opengl::Texture::Format::Red; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_R8; - break; - case GDT_UInt16: - format.glFormat = GL_R16UI; - break; - case GDT_Int16: - format.glFormat = GL_R16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_R32UI; - break; - case GDT_Int32: - format.glFormat = GL_R32I; - break; - case GDT_Float32: - format.glFormat = GL_R32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 2: - format.ghoulFormat = ghoul::opengl::Texture::Format::RG; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RG8; - break; - case GDT_UInt16: - format.glFormat = GL_RG16UI; - break; - case GDT_Int16: - format.glFormat = GL_RG16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RG32UI; - break; - case GDT_Int32: - format.glFormat = GL_RG32I; - break; - case GDT_Float32: - format.glFormat = GL_RG32F; - break; - case GDT_Float64: - format.glFormat = GL_RED; - break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 3: - format.ghoulFormat = ghoul::opengl::Texture::Format::RGB; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGB8; - break; - case GDT_UInt16: - format.glFormat = GL_RGB16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGB32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGB32I; - break; - case GDT_Float32: - format.glFormat = GL_RGB32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 4: - format.ghoulFormat = ghoul::opengl::Texture::Format::RGBA; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGBA8; - break; - case GDT_UInt16: - format.glFormat = GL_RGBA16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGBA32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGBA32I; - break; - case GDT_Float32: - format.glFormat = GL_RGBA32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - default: - LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); - break; - } - return format; -} - -TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType) { - TextureFormat format; - - switch (rasterCount) { - case 1: // Red - format.ghoulFormat = ghoul::opengl::Texture::Format::Red; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_R8; - break; - case GDT_UInt16: - format.glFormat = GL_R16UI; - break; - case GDT_Int16: - format.glFormat = GL_R16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_R32UI; - break; - case GDT_Int32: - format.glFormat = GL_R32I; - break; - case GDT_Float32: - format.glFormat = GL_R32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 2: - format.ghoulFormat = ghoul::opengl::Texture::Format::RG; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RG8; - break; - case GDT_UInt16: - format.glFormat = GL_RG16UI; - break; - case GDT_Int16: - format.glFormat = GL_RG16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RG32UI; - break; - case GDT_Int32: - format.glFormat = GL_RG32I; - break; - case GDT_Float32: - format.glFormat = GL_RG32F; - break; - case GDT_Float64: - format.glFormat = GL_RED; - break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 3: - format.ghoulFormat = ghoul::opengl::Texture::Format::BGR; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGB8; - break; - case GDT_UInt16: - format.glFormat = GL_RGB16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGB32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGB32I; - break; - case GDT_Float32: - format.glFormat = GL_RGB32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - case 4: - format.ghoulFormat = ghoul::opengl::Texture::Format::BGRA; - switch (gdalType) { - case GDT_Byte: - format.glFormat = GL_RGBA8; - break; - case GDT_UInt16: - format.glFormat = GL_RGBA16UI; - break; - case GDT_Int16: - format.glFormat = GL_RGB16_SNORM; - break; - case GDT_UInt32: - format.glFormat = GL_RGBA32UI; - break; - case GDT_Int32: - format.glFormat = GL_RGBA32I; - break; - case GDT_Float32: - format.glFormat = GL_RGBA32F; - break; - // No representation of 64 bit float? - //case GDT_Float64: - // format.glFormat = GL_RED; - // break; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - } - break; - default: - LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); - break; - } - return format; -} - -GLenum getOpenGLDataType(GDALDataType gdalType) { - switch (gdalType) { - case GDT_Byte: - return GL_UNSIGNED_BYTE; - case GDT_UInt16: - return GL_UNSIGNED_SHORT; - case GDT_Int16: - return GL_SHORT; - case GDT_UInt32: - return GL_UNSIGNED_INT; - case GDT_Int32: - return GL_INT; - case GDT_Float32: - return GL_FLOAT; - case GDT_Float64: - return GL_DOUBLE; - default: - LERROR("GDAL data type unknown to OpenGL: " << gdalType); - return GL_UNSIGNED_BYTE; - } -} - -GDALDataType getGdalDataType(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: - return GDT_Byte; - case GL_UNSIGNED_SHORT: - return GDT_UInt16; - case GL_SHORT: - return GDT_Int16; - case GL_UNSIGNED_INT: - return GDT_UInt32; - case GL_INT: - return GDT_Int32; - case GL_FLOAT: - return GDT_Float32; - case GL_DOUBLE: - return GDT_Float64; - default: - LERROR("OpenGL data type unknown to GDAL: " << glType); - return GDT_Unknown; - } -} - -#endif // GLOBEBROWSING_USE_GDAL - -size_t numberOfRasters(ghoul::opengl::Texture::Format format) { - switch (format) { - case ghoul::opengl::Texture::Format::Red: return 1; - case ghoul::opengl::Texture::Format::RG: return 2; - case ghoul::opengl::Texture::Format::RGB:; // Intentional fallthrough - case ghoul::opengl::Texture::Format::BGR: return 3; - case ghoul::opengl::Texture::Format::RGBA:; // Intentional fallthrough - case ghoul::opengl::Texture::Format::BGRA: return 4; - default: ghoul_assert(false, "Unknown format"); - } -} - -size_t numberOfBytes(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: return sizeof(GLubyte); - case GL_BYTE: return sizeof(GLbyte); - case GL_UNSIGNED_SHORT: return sizeof(GLushort); - case GL_SHORT: return sizeof(GLshort); - case GL_UNSIGNED_INT: return sizeof(GLuint); - case GL_INT: return sizeof(GLint); - case GL_HALF_FLOAT: return sizeof(GLhalf); - case GL_FLOAT: return sizeof(GLfloat); - case GL_DOUBLE: return sizeof(GLdouble); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -size_t getMaximumValue(GLenum glType) { - switch (glType) { - case GL_UNSIGNED_BYTE: - return 1 << 8; - case GL_UNSIGNED_SHORT: - return 1 << 16; - case GL_SHORT: - return 1 << 15; - case GL_UNSIGNED_INT: - return size_t(1) << 32; - case GL_INT: - return 1 << 31; - default: - ghoul_assert(false, "Unknown data type"); - } -} - -float interpretFloat(GLenum glType, const char* src) { - switch (glType) { - case GL_UNSIGNED_BYTE: - return static_cast(*reinterpret_cast(src)); - case GL_UNSIGNED_SHORT: - return static_cast(*reinterpret_cast(src)); - case GL_SHORT: - return static_cast(*reinterpret_cast(src)); - case GL_UNSIGNED_INT: - return static_cast(*reinterpret_cast(src)); - case GL_INT: - return static_cast(*reinterpret_cast(src)); - case GL_HALF_FLOAT: - return static_cast(*reinterpret_cast(src)); - case GL_FLOAT: - return static_cast(*reinterpret_cast(src)); - case GL_DOUBLE: - return static_cast(*reinterpret_cast(src)); - default: - ghoul_assert(false, "Unknown data type"); - } -} - -GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format) { - switch (format) { - case ghoul::opengl::Texture::Format::Red: - switch (glType) { - case GL_BYTE: - return GL_R8; - case GL_UNSIGNED_BYTE: - return GL_R8; - case GL_INT: - return GL_R32I; - case GL_UNSIGNED_INT: - return GL_R32UI; - case GL_FLOAT: - return GL_R32F; - case GL_HALF_FLOAT: - return GL_R16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::RG: - switch (glType) { - case GL_BYTE: - return GL_RG8; - case GL_UNSIGNED_BYTE: - return GL_RG8; - case GL_INT: - return GL_RG32I; - case GL_UNSIGNED_INT: - return GL_RG32UI; - case GL_FLOAT: - return GL_RG32F; - case GL_HALF_FLOAT: - return GL_RG16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::RGB: - switch (glType) { - case GL_BYTE: - return GL_RGB8; - case GL_UNSIGNED_BYTE: - return GL_RGB8; - case GL_INT: - return GL_RGB32I; - case GL_UNSIGNED_INT: - return GL_RGB32UI; - case GL_FLOAT: - return GL_RGB32F; - case GL_HALF_FLOAT: - return GL_RGB16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::RGBA: - switch (glType) { - case GL_BYTE: - return GL_RGBA8; - case GL_UNSIGNED_BYTE: - return GL_RGBA8; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - case GL_FLOAT: - return GL_RGBA32F; - case GL_HALF_FLOAT: - return GL_RGBA16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::BGR: - switch (glType) { - case GL_BYTE: - return GL_RGB8; - case GL_UNSIGNED_BYTE: - return GL_RGB8; - case GL_INT: - return GL_RGB32I; - case GL_UNSIGNED_INT: - return GL_RGB32UI; - case GL_FLOAT: - return GL_RGB32F; - case GL_HALF_FLOAT: - return GL_RGB16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - case ghoul::opengl::Texture::Format::BGRA: - switch (glType) { - case GL_BYTE: - return GL_RGBA8; - case GL_UNSIGNED_BYTE: - return GL_RGBA8; - case GL_INT: - return GL_RGBA32I; - case GL_UNSIGNED_INT: - return GL_RGBA32UI; - case GL_FLOAT: - return GL_RGBA32F; - case GL_HALF_FLOAT: - return GL_RGBA16F; - default: - ghoul_assert(false, "glType data type unknown"); - LERROR("glType data type unknown: " << glType); - return GLenum(0); - } - break; - default: - LERROR( - "Unknown format for OpenGL texture: " << - static_cast - >(format) - ); - return GLenum(0); - break; - } -} - -} // namespace tiledatatype -} // namespace globebrowsing -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#ifdef GLOBEBROWSING_USE_GDAL +#include +#include +#endif // GLOBEBROWSING_USE_GDAL + +#include +#include // abspath +#include + +#include + +#include + +#include +#include + +namespace { + const char* _loggerCat = "TileDataType"; +} + +namespace openspace { +namespace globebrowsing { +namespace tiledatatype { + +#ifdef GLOBEBROWSING_USE_GDAL + +float interpretFloat(GDALDataType gdalType, const char* src) { + switch (gdalType) { + case GDT_Byte: + return static_cast(*reinterpret_cast(src)); + case GDT_UInt16: + return static_cast(*reinterpret_cast(src)); + case GDT_Int16: + return static_cast(*reinterpret_cast(src)); + case GDT_UInt32: + return static_cast(*reinterpret_cast(src)); + case GDT_Int32: + return static_cast(*reinterpret_cast(src)); + case GDT_Float32: + return static_cast(*reinterpret_cast(src)); + case GDT_Float64: + return static_cast(*reinterpret_cast(src)); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +size_t numberOfBytes(GDALDataType gdalType) { + switch (gdalType) { + case GDT_Byte: + return sizeof(GLubyte); + case GDT_UInt16: + return sizeof(GLushort); + case GDT_Int16: + return sizeof(GLshort); + case GDT_UInt32: + return sizeof(GLuint); + case GDT_Int32: + return sizeof(GLint); + case GDT_Float32: + return sizeof(GLfloat); + case GDT_Float64: + return sizeof(GLdouble); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +size_t getMaximumValue(GDALDataType gdalType) { + switch (gdalType) { + case GDT_Byte: + return 1 << 8; + case GDT_UInt16: + return 1 << 16; + case GDT_Int16: + return 1 << 15; + case GDT_UInt32: + return size_t(1) << 32; + case GDT_Int32: + return 1 << 31; + default: + ghoul_assert(false, "Unknown data type"); + } +} + +TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType) { + TextureFormat format; + + switch (rasterCount) { + case 1: // Red + format.ghoulFormat = ghoul::opengl::Texture::Format::Red; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_R8; + break; + case GDT_UInt16: + format.glFormat = GL_R16UI; + break; + case GDT_Int16: + format.glFormat = GL_R16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_R32UI; + break; + case GDT_Int32: + format.glFormat = GL_R32I; + break; + case GDT_Float32: + format.glFormat = GL_R32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 2: + format.ghoulFormat = ghoul::opengl::Texture::Format::RG; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RG8; + break; + case GDT_UInt16: + format.glFormat = GL_RG16UI; + break; + case GDT_Int16: + format.glFormat = GL_RG16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RG32UI; + break; + case GDT_Int32: + format.glFormat = GL_RG32I; + break; + case GDT_Float32: + format.glFormat = GL_RG32F; + break; + case GDT_Float64: + format.glFormat = GL_RED; + break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 3: + format.ghoulFormat = ghoul::opengl::Texture::Format::RGB; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGB8; + break; + case GDT_UInt16: + format.glFormat = GL_RGB16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGB32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGB32I; + break; + case GDT_Float32: + format.glFormat = GL_RGB32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 4: + format.ghoulFormat = ghoul::opengl::Texture::Format::RGBA; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGBA8; + break; + case GDT_UInt16: + format.glFormat = GL_RGBA16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGBA32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGBA32I; + break; + case GDT_Float32: + format.glFormat = GL_RGBA32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + default: + LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); + break; + } + return format; +} + +TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType) { + TextureFormat format; + + switch (rasterCount) { + case 1: // Red + format.ghoulFormat = ghoul::opengl::Texture::Format::Red; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_R8; + break; + case GDT_UInt16: + format.glFormat = GL_R16UI; + break; + case GDT_Int16: + format.glFormat = GL_R16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_R32UI; + break; + case GDT_Int32: + format.glFormat = GL_R32I; + break; + case GDT_Float32: + format.glFormat = GL_R32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 2: + format.ghoulFormat = ghoul::opengl::Texture::Format::RG; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RG8; + break; + case GDT_UInt16: + format.glFormat = GL_RG16UI; + break; + case GDT_Int16: + format.glFormat = GL_RG16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RG32UI; + break; + case GDT_Int32: + format.glFormat = GL_RG32I; + break; + case GDT_Float32: + format.glFormat = GL_RG32F; + break; + case GDT_Float64: + format.glFormat = GL_RED; + break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 3: + format.ghoulFormat = ghoul::opengl::Texture::Format::BGR; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGB8; + break; + case GDT_UInt16: + format.glFormat = GL_RGB16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGB32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGB32I; + break; + case GDT_Float32: + format.glFormat = GL_RGB32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + case 4: + format.ghoulFormat = ghoul::opengl::Texture::Format::BGRA; + switch (gdalType) { + case GDT_Byte: + format.glFormat = GL_RGBA8; + break; + case GDT_UInt16: + format.glFormat = GL_RGBA16UI; + break; + case GDT_Int16: + format.glFormat = GL_RGB16_SNORM; + break; + case GDT_UInt32: + format.glFormat = GL_RGBA32UI; + break; + case GDT_Int32: + format.glFormat = GL_RGBA32I; + break; + case GDT_Float32: + format.glFormat = GL_RGBA32F; + break; + // No representation of 64 bit float? + //case GDT_Float64: + // format.glFormat = GL_RED; + // break; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + } + break; + default: + LERROR("Unknown number of channels for OpenGL texture: " << rasterCount); + break; + } + return format; +} + +GLenum getOpenGLDataType(GDALDataType gdalType) { + switch (gdalType) { + case GDT_Byte: + return GL_UNSIGNED_BYTE; + case GDT_UInt16: + return GL_UNSIGNED_SHORT; + case GDT_Int16: + return GL_SHORT; + case GDT_UInt32: + return GL_UNSIGNED_INT; + case GDT_Int32: + return GL_INT; + case GDT_Float32: + return GL_FLOAT; + case GDT_Float64: + return GL_DOUBLE; + default: + LERROR("GDAL data type unknown to OpenGL: " << gdalType); + return GL_UNSIGNED_BYTE; + } +} + +GDALDataType getGdalDataType(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return GDT_Byte; + case GL_UNSIGNED_SHORT: + return GDT_UInt16; + case GL_SHORT: + return GDT_Int16; + case GL_UNSIGNED_INT: + return GDT_UInt32; + case GL_INT: + return GDT_Int32; + case GL_FLOAT: + return GDT_Float32; + case GL_DOUBLE: + return GDT_Float64; + default: + LERROR("OpenGL data type unknown to GDAL: " << glType); + return GDT_Unknown; + } +} + +#endif // GLOBEBROWSING_USE_GDAL + +size_t numberOfRasters(ghoul::opengl::Texture::Format format) { + switch (format) { + case ghoul::opengl::Texture::Format::Red: return 1; + case ghoul::opengl::Texture::Format::RG: return 2; + case ghoul::opengl::Texture::Format::RGB:; // Intentional fallthrough + case ghoul::opengl::Texture::Format::BGR: return 3; + case ghoul::opengl::Texture::Format::RGBA:; // Intentional fallthrough + case ghoul::opengl::Texture::Format::BGRA: return 4; + default: ghoul_assert(false, "Unknown format"); + } +} + +size_t numberOfBytes(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_BYTE: return sizeof(GLbyte); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_SHORT: return sizeof(GLshort); + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_INT: return sizeof(GLint); + case GL_HALF_FLOAT: return sizeof(GLhalf); + case GL_FLOAT: return sizeof(GLfloat); + case GL_DOUBLE: return sizeof(GLdouble); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +size_t getMaximumValue(GLenum glType) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return 1 << 8; + case GL_UNSIGNED_SHORT: + return 1 << 16; + case GL_SHORT: + return 1 << 15; + case GL_UNSIGNED_INT: + return size_t(1) << 32; + case GL_INT: + return 1 << 31; + default: + ghoul_assert(false, "Unknown data type"); + } +} + +float interpretFloat(GLenum glType, const char* src) { + switch (glType) { + case GL_UNSIGNED_BYTE: + return static_cast(*reinterpret_cast(src)); + case GL_UNSIGNED_SHORT: + return static_cast(*reinterpret_cast(src)); + case GL_SHORT: + return static_cast(*reinterpret_cast(src)); + case GL_UNSIGNED_INT: + return static_cast(*reinterpret_cast(src)); + case GL_INT: + return static_cast(*reinterpret_cast(src)); + case GL_HALF_FLOAT: + return static_cast(*reinterpret_cast(src)); + case GL_FLOAT: + return static_cast(*reinterpret_cast(src)); + case GL_DOUBLE: + return static_cast(*reinterpret_cast(src)); + default: + ghoul_assert(false, "Unknown data type"); + } +} + +GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format) { + switch (format) { + case ghoul::opengl::Texture::Format::Red: + switch (glType) { + case GL_BYTE: + return GL_R8; + case GL_UNSIGNED_BYTE: + return GL_R8; + case GL_INT: + return GL_R32I; + case GL_UNSIGNED_INT: + return GL_R32UI; + case GL_FLOAT: + return GL_R32F; + case GL_HALF_FLOAT: + return GL_R16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::RG: + switch (glType) { + case GL_BYTE: + return GL_RG8; + case GL_UNSIGNED_BYTE: + return GL_RG8; + case GL_INT: + return GL_RG32I; + case GL_UNSIGNED_INT: + return GL_RG32UI; + case GL_FLOAT: + return GL_RG32F; + case GL_HALF_FLOAT: + return GL_RG16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::RGB: + switch (glType) { + case GL_BYTE: + return GL_RGB8; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_INT: + return GL_RGB32I; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::RGBA: + switch (glType) { + case GL_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::BGR: + switch (glType) { + case GL_BYTE: + return GL_RGB8; + case GL_UNSIGNED_BYTE: + return GL_RGB8; + case GL_INT: + return GL_RGB32I; + case GL_UNSIGNED_INT: + return GL_RGB32UI; + case GL_FLOAT: + return GL_RGB32F; + case GL_HALF_FLOAT: + return GL_RGB16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + case ghoul::opengl::Texture::Format::BGRA: + switch (glType) { + case GL_BYTE: + return GL_RGBA8; + case GL_UNSIGNED_BYTE: + return GL_RGBA8; + case GL_INT: + return GL_RGBA32I; + case GL_UNSIGNED_INT: + return GL_RGBA32UI; + case GL_FLOAT: + return GL_RGBA32F; + case GL_HALF_FLOAT: + return GL_RGBA16F; + default: + ghoul_assert(false, "glType data type unknown"); + LERROR("glType data type unknown: " << glType); + return GLenum(0); + } + break; + default: + LERROR( + "Unknown format for OpenGL texture: " << + static_cast + >(format) + ); + return GLenum(0); + break; + } +} + +} // namespace tiledatatype +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h index a0961bd6d0..7476b018e8 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.h @@ -1,61 +1,61 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ - -#include -#include - -#include - -#ifdef GLOBEBROWSING_USE_GDAL -#include -#endif // GLOBEBROWSING_USE_GDAL - -namespace openspace { -namespace globebrowsing { -namespace tiledatatype { - -#ifdef GLOBEBROWSING_USE_GDAL - GLenum getOpenGLDataType(GDALDataType gdalType); -GDALDataType getGdalDataType(GLenum glType); -TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType); -TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType); -size_t getMaximumValue(GDALDataType gdalType); -size_t numberOfBytes(GDALDataType gdalType); -float interpretFloat(GDALDataType gdalType, const char* src); -#endif // GLOBEBROWSING_USE_GDAL - -GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format); -size_t numberOfRasters(ghoul::opengl::Texture::Format format); -size_t numberOfBytes(GLenum glType); -size_t getMaximumValue(GLenum glType); -float interpretFloat(GLenum glType, const char* src); - -} // namespace tiledatatype -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ + +#include +#include + +#include + +#ifdef GLOBEBROWSING_USE_GDAL +#include +#endif // GLOBEBROWSING_USE_GDAL + +namespace openspace { +namespace globebrowsing { +namespace tiledatatype { + +#ifdef GLOBEBROWSING_USE_GDAL + GLenum getOpenGLDataType(GDALDataType gdalType); +GDALDataType getGdalDataType(GLenum glType); +TextureFormat getTextureFormat(int rasterCount, GDALDataType gdalType); +TextureFormat getTextureFormatOptimized(int rasterCount, GDALDataType gdalType); +size_t getMaximumValue(GDALDataType gdalType); +size_t numberOfBytes(GDALDataType gdalType); +float interpretFloat(GDALDataType gdalType, const char* src); +#endif // GLOBEBROWSING_USE_GDAL + +GLenum glTextureFormat(GLenum glType, ghoul::opengl::Texture::Format format); +size_t numberOfRasters(ghoul::opengl::Texture::Format format); +size_t numberOfBytes(GLenum glType); +size_t getMaximumValue(GLenum glType); +float interpretFloat(GLenum glType, const char* src); + +} // namespace tiledatatype +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_DATA_TYPE___H__ diff --git a/modules/globebrowsing/tile/textureformat.h b/modules/globebrowsing/tile/textureformat.h index 607a804faf..a8a9aa9bb3 100644 --- a/modules/globebrowsing/tile/textureformat.h +++ b/modules/globebrowsing/tile/textureformat.h @@ -1,43 +1,43 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ - -#include -#include - -namespace openspace { -namespace globebrowsing { - -struct TextureFormat { - ghoul::opengl::Texture::Format ghoulFormat; - GLenum glFormat; -}; - - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ + +#include +#include + +namespace openspace { +namespace globebrowsing { + +struct TextureFormat { + ghoul::opengl::Texture::Format ghoulFormat; + GLenum glFormat; +}; + + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TEXTUREFORMAT___H__ diff --git a/modules/globebrowsing/tile/tiletextureinitdata.cpp b/modules/globebrowsing/tile/tiletextureinitdata.cpp index 31045b8534..eddc426296 100644 --- a/modules/globebrowsing/tile/tiletextureinitdata.cpp +++ b/modules/globebrowsing/tile/tiletextureinitdata.cpp @@ -1,152 +1,152 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include - -namespace openspace { -namespace globebrowsing { - -const glm::ivec2 TileTextureInitData::tilePixelStartOffset = glm::ivec2(-2); -const glm::ivec2 TileTextureInitData::tilePixelSizeDifference = glm::ivec2(4); - -TileTextureInitData::TileTextureInitData(size_t width, size_t height, GLenum glType, - Format textureFormat, ShouldAllocateDataOnCPU shouldAllocateDataOnCPU) - : _glType(glType) - , _ghoulTextureFormat(textureFormat) - , _shouldAllocateDataOnCPU(shouldAllocateDataOnCPU) -{ - _dimensionsWithoutPadding = glm::ivec3(width, height, 1); - _dimensionsWithPadding = glm::ivec3( - width + tilePixelSizeDifference.x, height + tilePixelSizeDifference.y, 1); - _nRasters = tiledatatype::numberOfRasters(_ghoulTextureFormat); - _bytesPerDatum = tiledatatype::numberOfBytes(glType); - _bytesPerPixel = _nRasters * _bytesPerDatum; - _bytesPerLine = _bytesPerPixel * _dimensionsWithPadding.x; - _totalNumBytes = _bytesPerLine * _dimensionsWithPadding.y; - _glTextureFormat = tiledatatype::glTextureFormat(_glType, - _ghoulTextureFormat); - calculateHashKey(); -}; - -TileTextureInitData::TileTextureInitData(const TileTextureInitData& original) - : TileTextureInitData( - original.dimensionsWithoutPadding().x, - original.dimensionsWithoutPadding().y, - original.glType(), - original.ghoulTextureFormat(), - original.shouldAllocateDataOnCPU() ? ShouldAllocateDataOnCPU::Yes : ShouldAllocateDataOnCPU::No) -{ }; - -glm::ivec3 TileTextureInitData::dimensionsWithPadding() const { - return _dimensionsWithPadding; -} - -glm::ivec3 TileTextureInitData::dimensionsWithoutPadding() const { - return _dimensionsWithoutPadding; -} - -size_t TileTextureInitData::nRasters() const { - return _nRasters; -} - -size_t TileTextureInitData::bytesPerDatum() const { - return _bytesPerDatum; -} - -size_t TileTextureInitData::bytesPerPixel() const { - return _bytesPerPixel; -} - -size_t TileTextureInitData::bytesPerLine() const { - return _bytesPerLine; -} - -size_t TileTextureInitData::totalNumBytes() const { - return _totalNumBytes; -} - -GLenum TileTextureInitData::glType() const { - return _glType; -} - -TileTextureInitData::Format TileTextureInitData::ghoulTextureFormat() const { - return _ghoulTextureFormat; -} - -GLenum TileTextureInitData::glTextureFormat() const { - return _glTextureFormat; -} - -bool TileTextureInitData::shouldAllocateDataOnCPU() const { - return _shouldAllocateDataOnCPU; -} - -TileTextureInitData::HashKey TileTextureInitData::hashKey() const { - return _hashKey; -} - -void TileTextureInitData::calculateHashKey() { - ghoul_assert(_dimensionsWithoutPadding.x > 0, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.y > 0, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.x <= 1024, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.y <= 1024, "Incorrect dimension"); - ghoul_assert(_dimensionsWithoutPadding.z == 1, "Incorrect dimension"); - unsigned int format = getUniqueIdFromTextureFormat(_ghoulTextureFormat); - ghoul_assert(format < 256, "Incorrect format"); - - _hashKey = 0LL; - - _hashKey |= _dimensionsWithoutPadding.x; - _hashKey |= _dimensionsWithoutPadding.y << 10; - _hashKey |= static_cast>(_glType) << (10 + 16); - _hashKey |= format << (10 + 16 + 4); -}; - -unsigned int TileTextureInitData::getUniqueIdFromTextureFormat( - Format textureFormat) const -{ - using Format = Format; - switch (textureFormat) { - case Format::Red: - return 0; - case Format::RG: - return 1; - case Format::RGB: - return 2; - case Format::BGR: - return 3; - case Format::RGBA: - return 4; - case Format::BGRA: - return 5; - case Format::DepthComponent: - return 6; - default: - ghoul_assert(false, "Unknown texture format"); - } -} - -} // namespace globebrowsing -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +namespace openspace { +namespace globebrowsing { + +const glm::ivec2 TileTextureInitData::tilePixelStartOffset = glm::ivec2(-2); +const glm::ivec2 TileTextureInitData::tilePixelSizeDifference = glm::ivec2(4); + +TileTextureInitData::TileTextureInitData(size_t width, size_t height, GLenum glType, + Format textureFormat, ShouldAllocateDataOnCPU shouldAllocateDataOnCPU) + : _glType(glType) + , _ghoulTextureFormat(textureFormat) + , _shouldAllocateDataOnCPU(shouldAllocateDataOnCPU) +{ + _dimensionsWithoutPadding = glm::ivec3(width, height, 1); + _dimensionsWithPadding = glm::ivec3( + width + tilePixelSizeDifference.x, height + tilePixelSizeDifference.y, 1); + _nRasters = tiledatatype::numberOfRasters(_ghoulTextureFormat); + _bytesPerDatum = tiledatatype::numberOfBytes(glType); + _bytesPerPixel = _nRasters * _bytesPerDatum; + _bytesPerLine = _bytesPerPixel * _dimensionsWithPadding.x; + _totalNumBytes = _bytesPerLine * _dimensionsWithPadding.y; + _glTextureFormat = tiledatatype::glTextureFormat(_glType, + _ghoulTextureFormat); + calculateHashKey(); +}; + +TileTextureInitData::TileTextureInitData(const TileTextureInitData& original) + : TileTextureInitData( + original.dimensionsWithoutPadding().x, + original.dimensionsWithoutPadding().y, + original.glType(), + original.ghoulTextureFormat(), + original.shouldAllocateDataOnCPU() ? ShouldAllocateDataOnCPU::Yes : ShouldAllocateDataOnCPU::No) +{ }; + +glm::ivec3 TileTextureInitData::dimensionsWithPadding() const { + return _dimensionsWithPadding; +} + +glm::ivec3 TileTextureInitData::dimensionsWithoutPadding() const { + return _dimensionsWithoutPadding; +} + +size_t TileTextureInitData::nRasters() const { + return _nRasters; +} + +size_t TileTextureInitData::bytesPerDatum() const { + return _bytesPerDatum; +} + +size_t TileTextureInitData::bytesPerPixel() const { + return _bytesPerPixel; +} + +size_t TileTextureInitData::bytesPerLine() const { + return _bytesPerLine; +} + +size_t TileTextureInitData::totalNumBytes() const { + return _totalNumBytes; +} + +GLenum TileTextureInitData::glType() const { + return _glType; +} + +TileTextureInitData::Format TileTextureInitData::ghoulTextureFormat() const { + return _ghoulTextureFormat; +} + +GLenum TileTextureInitData::glTextureFormat() const { + return _glTextureFormat; +} + +bool TileTextureInitData::shouldAllocateDataOnCPU() const { + return _shouldAllocateDataOnCPU; +} + +TileTextureInitData::HashKey TileTextureInitData::hashKey() const { + return _hashKey; +} + +void TileTextureInitData::calculateHashKey() { + ghoul_assert(_dimensionsWithoutPadding.x > 0, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.y > 0, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.x <= 1024, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.y <= 1024, "Incorrect dimension"); + ghoul_assert(_dimensionsWithoutPadding.z == 1, "Incorrect dimension"); + unsigned int format = getUniqueIdFromTextureFormat(_ghoulTextureFormat); + ghoul_assert(format < 256, "Incorrect format"); + + _hashKey = 0LL; + + _hashKey |= _dimensionsWithoutPadding.x; + _hashKey |= _dimensionsWithoutPadding.y << 10; + _hashKey |= static_cast>(_glType) << (10 + 16); + _hashKey |= format << (10 + 16 + 4); +}; + +unsigned int TileTextureInitData::getUniqueIdFromTextureFormat( + Format textureFormat) const +{ + using Format = Format; + switch (textureFormat) { + case Format::Red: + return 0; + case Format::RG: + return 1; + case Format::RGB: + return 2; + case Format::BGR: + return 3; + case Format::RGBA: + return 4; + case Format::BGRA: + return 5; + case Format::DepthComponent: + return 6; + default: + ghoul_assert(false, "Unknown texture format"); + } +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tiletextureinitdata.h b/modules/globebrowsing/tile/tiletextureinitdata.h index 874e232933..8dd27c8b0c 100644 --- a/modules/globebrowsing/tile/tiletextureinitdata.h +++ b/modules/globebrowsing/tile/tiletextureinitdata.h @@ -1,91 +1,91 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ - -#include -#include -#include - -#include - -namespace openspace { -namespace globebrowsing { - -/** - * All information needed to create a texture used for a Tile. - */ -class TileTextureInitData -{ -public: - using HashKey = unsigned long long; - using ShouldAllocateDataOnCPU = ghoul::Boolean; - using Format = ghoul::opengl::Texture::Format; - - TileTextureInitData(size_t width, size_t height, GLenum glType, Format textureFormat, - ShouldAllocateDataOnCPU shouldAllocateDataOnCPU = ShouldAllocateDataOnCPU::No); - - TileTextureInitData(const TileTextureInitData& original); - - ~TileTextureInitData() = default; - - glm::ivec3 dimensionsWithPadding() const; - glm::ivec3 dimensionsWithoutPadding() const; - size_t nRasters() const; - size_t bytesPerDatum() const; - size_t bytesPerPixel() const; - size_t bytesPerLine() const; - size_t totalNumBytes() const; - GLenum glType() const; - Format ghoulTextureFormat() const; - GLenum glTextureFormat() const; - bool shouldAllocateDataOnCPU() const; - HashKey hashKey() const; - - const static glm::ivec2 tilePixelStartOffset; - const static glm::ivec2 tilePixelSizeDifference; - -private: - void calculateHashKey(); - unsigned int getUniqueIdFromTextureFormat(Format textureFormat) const; - - HashKey _hashKey; - glm::ivec3 _dimensionsWithPadding; - glm::ivec3 _dimensionsWithoutPadding; - GLenum _glType; - Format _ghoulTextureFormat; - GLenum _glTextureFormat; - size_t _nRasters; - size_t _bytesPerDatum; - size_t _bytesPerPixel; - size_t _bytesPerLine; - size_t _totalNumBytes; - bool _shouldAllocateDataOnCPU; -}; - -} // namespace globebrowsing -} // namespace openspace - -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ + +#include +#include +#include + +#include + +namespace openspace { +namespace globebrowsing { + +/** + * All information needed to create a texture used for a Tile. + */ +class TileTextureInitData +{ +public: + using HashKey = unsigned long long; + using ShouldAllocateDataOnCPU = ghoul::Boolean; + using Format = ghoul::opengl::Texture::Format; + + TileTextureInitData(size_t width, size_t height, GLenum glType, Format textureFormat, + ShouldAllocateDataOnCPU shouldAllocateDataOnCPU = ShouldAllocateDataOnCPU::No); + + TileTextureInitData(const TileTextureInitData& original); + + ~TileTextureInitData() = default; + + glm::ivec3 dimensionsWithPadding() const; + glm::ivec3 dimensionsWithoutPadding() const; + size_t nRasters() const; + size_t bytesPerDatum() const; + size_t bytesPerPixel() const; + size_t bytesPerLine() const; + size_t totalNumBytes() const; + GLenum glType() const; + Format ghoulTextureFormat() const; + GLenum glTextureFormat() const; + bool shouldAllocateDataOnCPU() const; + HashKey hashKey() const; + + const static glm::ivec2 tilePixelStartOffset; + const static glm::ivec2 tilePixelSizeDifference; + +private: + void calculateHashKey(); + unsigned int getUniqueIdFromTextureFormat(Format textureFormat) const; + + HashKey _hashKey; + glm::ivec3 _dimensionsWithPadding; + glm::ivec3 _dimensionsWithoutPadding; + GLenum _glType; + Format _ghoulTextureFormat; + GLenum _glTextureFormat; + size_t _nRasters; + size_t _bytesPerDatum; + size_t _bytesPerPixel; + size_t _bytesPerLine; + size_t _totalNumBytes; + bool _shouldAllocateDataOnCPU; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILE_TEXTURE_INIT_DATA___H__ diff --git a/modules/newhorizons/util/projectioncomponent.cpp b/modules/newhorizons/util/projectioncomponent.cpp index e31b2883c2..e22fee5148 100644 --- a/modules/newhorizons/util/projectioncomponent.cpp +++ b/modules/newhorizons/util/projectioncomponent.cpp @@ -1,950 +1,950 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace { - const char* keyPotentialTargets = "PotentialTargets"; - - const char* keyInstrument = "Instrument.Name"; - const char* keyInstrumentFovy = "Instrument.Fovy"; - const char* keyInstrumentAspect = "Instrument.Aspect"; - - const char* keyTranslation = "DataInputTranslation"; - - const char* keyProjObserver = "Observer"; - const char* keyProjTarget = "Target"; - const char* keyProjAberration = "Aberration"; - - const char* keySequenceDir = "Sequence"; - const char* keySequenceType = "SequenceType"; - - const char* keyNeedsTextureMapDilation = "TextureMap"; - const char* keyNeedsShadowing = "ShadowMap"; - const char* keyTextureMapAspectRatio = "AspectRatio"; - - const char* sequenceTypeImage = "image-sequence"; - const char* sequenceTypePlaybook = "playbook"; - const char* sequenceTypeHybrid = "hybrid"; - const char* sequenceTypeInstrumentTimes = "instrument-times"; - - const char* placeholderFile = - "${OPENSPACE_DATA}/scene/common/textures/placeholder.png"; - - const char* _loggerCat = "ProjectionComponent"; -} - -namespace openspace { - -using ghoul::Dictionary; -using glm::ivec2; - -documentation::Documentation ProjectionComponent::Documentation() { - using namespace documentation; - return { - "Projection Component", - "newhorizons_projectioncomponent", - { - { - keyInstrument, - new StringAnnotationVerifier("A SPICE name of an instrument"), - "The instrument that is used to perform the projections", - Optional::No - }, - { - keyInstrumentFovy, - new DoubleVerifier, - "The field of view in degrees along the y axis", - Optional::No - }, - { - keyInstrumentAspect, - new DoubleVerifier, - "The aspect ratio of the instrument in relation between x and y axis", - Optional::No - }, - { - keyProjObserver, - new StringAnnotationVerifier("A SPICE name of the observing object"), - "The observer that is doing the projection. This has to be a valid SPICE " - "name or SPICE integer.", - Optional::No - }, - { - keyProjTarget, - new StringAnnotationVerifier("A SPICE name of the observed object"), - "The observed object that is projected on. This has to be a valid SPICE " - "name or SPICE integer.", - Optional::No - }, - { - keyProjAberration, - new StringInListVerifier({ - // from SpiceManager::AberrationCorrection::AberrationCorrection - "NONE", "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S" - }), - "The aberration correction that is supposed to be used for the " - "projection. The values for the correction correspond to the SPICE " - "definition as described in " - "ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html", - Optional::No - }, - { - keyPotentialTargets, - new StringListVerifier, - "The list of potential targets that are involved with the image " - "projection", - Optional::Yes - }, - { - keyNeedsTextureMapDilation, - new BoolVerifier, - "Determines whether a dilation step of the texture map has to be " - "performed after each projection. This is necessary if the texture of " - "the projected object is a texture map where the borders are not " - "touching. The default value is 'false'.", - Optional::Yes - }, - { - keyNeedsShadowing, - new BoolVerifier, - "Determines whether the object requires a self-shadowing algorithm. This " - "is necessary if the object is concave and might cast a shadow on itself " - "during presentation. The default value is 'false'.", - Optional::Yes - }, - { - keyTextureMapAspectRatio, - new DoubleVerifier, - "Sets the desired aspect ratio of the projected texture. This might be " - "necessary as planets usually have 2x1 aspect ratios, whereas this does " - "not hold for non-planet objects (comets, asteroids, etc). The default " - "value is '1.0'.", - Optional::Yes - } - - } - }; -} - -ProjectionComponent::ProjectionComponent() - : properties::PropertyOwner("ProjectionComponent") - , _performProjection("performProjection", "Perform Projections", true) - , _clearAllProjections("clearAllProjections", "Clear Projections", false) - , _projectionFading("projectionFading", "Projection Fading", 1.f, 0.f, 1.f) - , _textureSize("textureSize", "Texture Size", ivec2(16), ivec2(16), ivec2(32768)) - , _applyTextureSize("applyTextureSize", "Apply Texture Size") - , _textureSizeDirty(false) - , _projectionTexture(nullptr) -{ - _shadowing.isEnabled = false; - _dilation.isEnabled = false; - - addProperty(_performProjection); - addProperty(_clearAllProjections); - addProperty(_projectionFading); - - addProperty(_textureSize); - addProperty(_applyTextureSize); - _applyTextureSize.onChange([this]() { _textureSizeDirty = true; }); -} - -void ProjectionComponent::initialize(const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ProjectionComponent" - ); - _instrumentID = dictionary.value(keyInstrument); - _projectorID = dictionary.value(keyProjObserver); - _projecteeID = dictionary.value(keyProjTarget); - _fovy = static_cast(dictionary.value(keyInstrumentFovy)); - _aspectRatio = static_cast(dictionary.value(keyInstrumentAspect)); - - _aberration = SpiceManager::AberrationCorrection( - dictionary.value(keyProjAberration) - ); - - if (dictionary.hasKeyAndValue(keyPotentialTargets)) { - ghoul::Dictionary potentialTargets = dictionary.value( - keyPotentialTargets - ); - - _potentialTargets.reserve(potentialTargets.size()); - for (int i = 1; i <= potentialTargets.size(); ++i) { - _potentialTargets.emplace_back( - potentialTargets.value(std::to_string(i)) - ); - } - } - - if (dictionary.hasKeyAndValue(keyNeedsTextureMapDilation)) { - _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation); - } - - if (dictionary.hasKeyAndValue(keyNeedsShadowing)) { - _shadowing.isEnabled = dictionary.value(keyNeedsShadowing); - } - - _projectionTextureAspectRatio = 1.f; - if (dictionary.hasKeyAndValue(keyTextureMapAspectRatio)) { - _projectionTextureAspectRatio = - static_cast(dictionary.value(keyTextureMapAspectRatio)); - } - - std::string name; - dictionary.getValue(SceneGraphNode::KeyName, name); - - std::vector parsers; - - std::string sequenceSource; - std::string sequenceType; - bool foundSequence = dictionary.getValue(keySequenceDir, sequenceSource); - if (foundSequence) { - sequenceSource = absPath(sequenceSource); - - dictionary.getValue(keySequenceType, sequenceType); - //Important: client must define translation-list in mod file IFF playbook - if (dictionary.hasKey(keyTranslation)) { - ghoul::Dictionary translationDictionary; - //get translation dictionary - dictionary.getValue(keyTranslation, translationDictionary); - - if (sequenceType == sequenceTypePlaybook) { - parsers.push_back(new HongKangParser( - name, - sequenceSource, - _projectorID, - translationDictionary, - _potentialTargets)); - } - else if (sequenceType == sequenceTypeImage) { - parsers.push_back(new LabelParser( - name, - sequenceSource, - translationDictionary)); - } - else if (sequenceType == sequenceTypeHybrid) { - //first read labels - parsers.push_back(new LabelParser( - name, - sequenceSource, - translationDictionary)); - - std::string _eventFile; - bool foundEventFile = dictionary.getValue("EventFile", _eventFile); - if (foundEventFile) { - //then read playbook - _eventFile = absPath(_eventFile); - parsers.push_back(new HongKangParser( - name, - _eventFile, - _projectorID, - translationDictionary, - _potentialTargets)); - } - else { - LWARNING("No eventfile has been provided, please check modfiles"); - } - } - else if (sequenceType == sequenceTypeInstrumentTimes) { - parsers.push_back(new InstrumentTimesParser( - name, - sequenceSource, - translationDictionary)); - } - - for (SequenceParser* parser : parsers) { - openspace::ImageSequencer::ref().runSequenceParser(parser); - delete parser; - } - } - else { - LWARNING("No playbook translation provided, please make sure all spice calls match playbook!"); - } - } -} - -bool ProjectionComponent::initializeGL() { - int maxSize = OpenGLCap.max2DTextureSize(); - glm::ivec2 size; - - if (_projectionTextureAspectRatio > 1.f) { - size.x = maxSize; - size.y = static_cast(maxSize / _projectionTextureAspectRatio); - } - else { - size.x = static_cast(maxSize * _projectionTextureAspectRatio); - size.y = maxSize; - } - - _textureSize.setMaxValue(size); - _textureSize = size / 2; - - // We only want to use half the resolution per default: - size /= 2; - - bool success = generateProjectionLayerTexture(size); - success &= generateDepthTexture(size); - success &= auxiliaryRendertarget(); - success &= depthRendertarget(); - - using std::unique_ptr; - using ghoul::opengl::Texture; - using ghoul::io::TextureReader; - - unique_ptr texture = TextureReader::ref().loadTexture(absPath(placeholderFile)); - if (texture) { - texture->uploadTexture(); - // TODO: AnisotropicMipMap crashes on ATI cards ---abock - //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - texture->setFilter(Texture::FilterMode::Linear); - texture->setWrapping(Texture::WrappingMode::ClampToBorder); - } - _placeholderTexture = std::move(texture); - - if (_dilation.isEnabled) { - _dilation.program = ghoul::opengl::ProgramObject::Build( - "Dilation", - "${MODULE_NEWHORIZONS}/shaders/dilation_vs.glsl", - "${MODULE_NEWHORIZONS}/shaders/dilation_fs.glsl" - ); - - const GLfloat plane[] = { - -1, -1, - 1, 1, - -1, 1, - -1, -1, - 1, -1, - 1, 1, - }; - - glGenVertexArrays(1, &_dilation.vao); - glGenBuffers(1, &_dilation.vbo); - - glBindVertexArray(_dilation.vao); - glBindBuffer(GL_ARRAY_BUFFER, _dilation.vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(plane), plane, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer( - 0, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(GLfloat) * 2, - reinterpret_cast(0) - ); - - glBindVertexArray(0); - } - - return success; -} - -bool ProjectionComponent::deinitialize() { - _projectionTexture = nullptr; - - glDeleteFramebuffers(1, &_fboID); - - if (_dilation.isEnabled) { - glDeleteFramebuffers(1, &_dilation.fbo); - glDeleteVertexArrays(1, &_dilation.vao); - glDeleteBuffers(1, &_dilation.vbo); - - _dilation.program = nullptr; - _dilation.texture = nullptr; - } - - return true; -} - -bool ProjectionComponent::isReady() const { - return (_projectionTexture != nullptr); -} - -void ProjectionComponent::imageProjectBegin() { - // keep handle to the current bound FBO - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); - - if (_textureSizeDirty) { - LDEBUG("Changing texture size to " << std::to_string(_textureSize)); - - // If the texture size has changed, we have to allocate new memory and copy - // the image texture to the new target - - using ghoul::opengl::Texture; - using ghoul::opengl::FramebufferObject; - - // Make a copy of the old textures - std::unique_ptr oldProjectionTexture = std::move(_projectionTexture); - std::unique_ptr oldDilationStencil = std::move(_dilation.stencilTexture); - std::unique_ptr oldDilationTexture = std::move(_dilation.texture); - std::unique_ptr oldDepthTexture = std::move(_shadowing.texture); - - // Generate the new textures - generateProjectionLayerTexture(_textureSize); - - if (_shadowing.isEnabled) { - generateDepthTexture(_textureSize); - } - - auto copyFramebuffers = [](Texture* src, Texture* dst, const std::string& msg) { - glFramebufferTexture( - GL_READ_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - *src, - 0 - ); - - GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Read Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glFramebufferTexture( - GL_DRAW_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - *dst, - 0 - ); - - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Draw Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glBlitFramebuffer( - 0, 0, - src->dimensions().x, src->dimensions().y, - 0, 0, - dst->dimensions().x, dst->dimensions().y, - GL_COLOR_BUFFER_BIT, - GL_LINEAR - ); - }; - - auto copyDepthBuffer = [](Texture* src, Texture* dst, const std::string& msg) { - glFramebufferTexture( - GL_READ_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - *src, - 0 - ); - - GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Read Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glFramebufferTexture( - GL_DRAW_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - *dst, - 0 - ); - - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); - if (!FramebufferObject::errorChecking(status).empty()) { - LERROR( - "Draw Buffer (" << msg << "): " << - FramebufferObject::errorChecking(status) - ); - } - - glBlitFramebuffer( - 0, 0, - src->dimensions().x, src->dimensions().y, - 0, 0, - dst->dimensions().x, dst->dimensions().y, - GL_DEPTH_BUFFER_BIT, - GL_NEAREST - ); - }; - - GLuint fbos[2]; - glGenFramebuffers(2, fbos); - glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); - - copyFramebuffers( - oldProjectionTexture.get(), - _projectionTexture.get(), - "Projection" - ); - - if (_dilation.isEnabled) { - copyFramebuffers( - oldDilationStencil.get(), - _dilation.stencilTexture.get(), - "Dilation Stencil" - ); - - copyFramebuffers( - oldDilationTexture.get(), - _dilation.texture.get(), - "Dilation Texture" - ); - } - - if (_shadowing.isEnabled) { - copyDepthBuffer( - oldDepthTexture.get(), - _shadowing.texture.get(), - "Shadowing" - ); - } - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glDeleteFramebuffers(2, fbos); - - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_projectionTexture, - 0 - ); - - if (_dilation.isEnabled) { - // We only need the stencil texture if we need to dilate - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT1, - GL_TEXTURE_2D, - *_dilation.stencilTexture, - 0 - ); - - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_dilation.texture, - 0 - ); - } - - if (_shadowing.isEnabled) { - glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - *_shadowing.texture, - 0 - ); - } - - _textureSizeDirty = false; - } - - glGetIntegerv(GL_VIEWPORT, _viewport); - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - - glViewport( - 0, 0, - static_cast(_projectionTexture->width()), - static_cast(_projectionTexture->height()) - ); - - if (_dilation.isEnabled) { - GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; - glDrawBuffers(2, buffers); - } -} - -bool ProjectionComponent::needsShadowMap() const { - return _shadowing.isEnabled; -} - -ghoul::opengl::Texture& ProjectionComponent::depthTexture() { - return *_shadowing.texture; -} - -void ProjectionComponent::depthMapRenderBegin() { - ghoul_assert(_shadowing.isEnabled, "Shadowing is not enabled"); - - // keep handle to the current bound FBO - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); - glGetIntegerv(GL_VIEWPORT, _viewport); - - glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); - glEnable(GL_DEPTH_TEST); - - glViewport( - 0, 0, - static_cast(_shadowing.texture->width()), - static_cast(_shadowing.texture->height()) - ); - - glClear(GL_DEPTH_BUFFER_BIT); -} - -void ProjectionComponent::depthMapRenderEnd() { - glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); - glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); -} - -void ProjectionComponent::imageProjectEnd() { - if (_dilation.isEnabled) { - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - - glDisable(GL_BLEND); - - ghoul::opengl::TextureUnit unit[2]; - unit[0].activate(); - _projectionTexture->bind(); - - unit[1].activate(); - _dilation.stencilTexture->bind(); - - _dilation.program->activate(); - _dilation.program->setUniform("tex", unit[0]); - _dilation.program->setUniform("stencil", unit[1]); - - glBindVertexArray(_dilation.vao); - glDrawArrays(GL_TRIANGLES, 0, 6); - - _dilation.program->deactivate(); - - glEnable(GL_BLEND); - } - - glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); - glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); -} - -void ProjectionComponent::update() { - if (_dilation.isEnabled && _dilation.program->isDirty()) { - _dilation.program->rebuildFromFile(); - } -} - -bool ProjectionComponent::depthRendertarget() { - GLint defaultFBO; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - // setup FBO - glGenFramebuffers(1, &_depthFboID); - glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - *_shadowing.texture, - 0); - - glDrawBuffer(GL_NONE); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) - return false; - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - return true; -} - -bool ProjectionComponent::auxiliaryRendertarget() { - bool completeSuccess = true; - - GLint defaultFBO; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - - // setup FBO - glGenFramebuffers(1, &_fboID); - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_projectionTexture, - 0 - ); - // check FBO status - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Main Framebuffer incomplete"); - completeSuccess &= false; - } - - - if (_dilation.isEnabled) { - // We only need the stencil texture if we need to dilate - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT1, - GL_TEXTURE_2D, - *_dilation.stencilTexture, - 0 - ); - - // check FBO status - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Main Framebuffer incomplete"); - completeSuccess &= false; - } - - glGenFramebuffers(1, &_dilation.fbo); - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - *_dilation.texture, - 0 - ); - - // check FBO status - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Dilation Framebuffer incomplete"); - completeSuccess &= false; - } - } - - // switch back to window-system-provided framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - - return completeSuccess; -} - -glm::mat4 ProjectionComponent::computeProjectorMatrix(const glm::vec3 loc, glm::dvec3 aim, - const glm::vec3 up, - const glm::dmat3& instrumentMatrix, - float fieldOfViewY, - float aspectRatio, - float nearPlane, float farPlane, - glm::vec3& boreSight) -{ - - //rotate boresight into correct alignment - boreSight = instrumentMatrix*aim; - glm::vec3 uptmp(instrumentMatrix*glm::dvec3(up)); - - // create view matrix - glm::vec3 e3 = glm::normalize(-boreSight); - glm::vec3 e1 = glm::normalize(glm::cross(uptmp, e3)); - glm::vec3 e2 = glm::normalize(glm::cross(e3, e1)); - - glm::mat4 projViewMatrix = glm::mat4(e1.x, e2.x, e3.x, 0.f, - e1.y, e2.y, e3.y, 0.f, - e1.z, e2.z, e3.z, 0.f, - glm::dot(e1, -loc), glm::dot(e2, -loc), glm::dot(e3, -loc), 1.f); - // create perspective projection matrix - glm::mat4 projProjectionMatrix = glm::perspective(glm::radians(fieldOfViewY), aspectRatio, nearPlane, farPlane); - - return projProjectionMatrix*projViewMatrix; -} - -bool ProjectionComponent::doesPerformProjection() const { - return _performProjection; -} - -bool ProjectionComponent::needsClearProjection() const { - return _clearAllProjections; -} - -float ProjectionComponent::projectionFading() const { - return _projectionFading; -} - -ghoul::opengl::Texture& ProjectionComponent::projectionTexture() const { - if (_dilation.isEnabled) { - return *_dilation.texture; - } - else { - return *_projectionTexture; - } -} - -std::string ProjectionComponent::projectorId() const { - return _projectorID; -} - -std::string ProjectionComponent::projecteeId() const { - return _projecteeID; -} - -std::string ProjectionComponent::instrumentId() const { - return _instrumentID; -} - -SpiceManager::AberrationCorrection ProjectionComponent::aberration() const { - return _aberration; -} - -float ProjectionComponent::fieldOfViewY() const { - return _fovy; -} - -float ProjectionComponent::aspectRatio() const { - return _aspectRatio; -} - -void ProjectionComponent::clearAllProjections() { - // keep handle to the current bound FBO - GLint defaultFBO; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); - - GLint m_viewport[4]; - glGetIntegerv(GL_VIEWPORT, m_viewport); - //counter = 0; - glViewport(0, 0, static_cast(_projectionTexture->width()), static_cast(_projectionTexture->height())); - - glBindFramebuffer(GL_FRAMEBUFFER, _fboID); - - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - - if (_dilation.isEnabled) { - glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); - glClear(GL_COLOR_BUFFER_BIT); - } - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); - glViewport(m_viewport[0], m_viewport[1], - m_viewport[2], m_viewport[3]); - - _clearAllProjections = false; -} - -std::shared_ptr ProjectionComponent::loadProjectionTexture( - const std::string& texturePath, - bool isPlaceholder) -{ - using std::unique_ptr; - using ghoul::opengl::Texture; - using ghoul::io::TextureReader; - - - if (isPlaceholder) { - return _placeholderTexture; - } - - - unique_ptr texture = TextureReader::ref().loadTexture(absPath(texturePath)); - if (texture) { - if (texture->format() == Texture::Format::Red) - ghoul::opengl::convertTextureFormat(*texture, Texture::Format::RGB); - texture->uploadTexture(); - // TODO: AnisotropicMipMap crashes on ATI cards ---abock - //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - texture->setFilter(Texture::FilterMode::Linear); - texture->setWrapping(Texture::WrappingMode::ClampToBorder); - } - return std::move(texture); -} - -bool ProjectionComponent::generateProjectionLayerTexture(const ivec2& size) { - LINFO( - "Creating projection texture of size '" << size.x << ", " << size.y << "'" - ); - _projectionTexture = std::make_unique ( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::RGBA - ); - if (_projectionTexture) { - _projectionTexture->uploadTexture(); - //_projectionTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - - if (_dilation.isEnabled) { - _dilation.texture = std::make_unique( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::RGBA - ); - - if (_dilation.texture) { - _dilation.texture->uploadTexture(); - //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - - _dilation.stencilTexture = std::make_unique( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::Red, - // @TODO: Remove the static cast ---abock - static_cast(ghoul::opengl::Texture::Format::Red) - ); - - if (_dilation.stencilTexture) { - _dilation.stencilTexture->uploadTexture(); - //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - } - - - return _projectionTexture != nullptr; - -} - -bool ProjectionComponent::generateDepthTexture(const ivec2& size) { - LINFO( - "Creating depth texture of size '" << size.x << ", " << size.y << "'" - ); - - _shadowing.texture = std::make_unique( - glm::uvec3(size, 1), - ghoul::opengl::Texture::Format::DepthComponent, - GL_DEPTH_COMPONENT32F - ); - - if (_shadowing.texture) { - _shadowing.texture->uploadTexture(); - } - - return _shadowing.texture != nullptr; - -} - -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + const char* keyPotentialTargets = "PotentialTargets"; + + const char* keyInstrument = "Instrument.Name"; + const char* keyInstrumentFovy = "Instrument.Fovy"; + const char* keyInstrumentAspect = "Instrument.Aspect"; + + const char* keyTranslation = "DataInputTranslation"; + + const char* keyProjObserver = "Observer"; + const char* keyProjTarget = "Target"; + const char* keyProjAberration = "Aberration"; + + const char* keySequenceDir = "Sequence"; + const char* keySequenceType = "SequenceType"; + + const char* keyNeedsTextureMapDilation = "TextureMap"; + const char* keyNeedsShadowing = "ShadowMap"; + const char* keyTextureMapAspectRatio = "AspectRatio"; + + const char* sequenceTypeImage = "image-sequence"; + const char* sequenceTypePlaybook = "playbook"; + const char* sequenceTypeHybrid = "hybrid"; + const char* sequenceTypeInstrumentTimes = "instrument-times"; + + const char* placeholderFile = + "${OPENSPACE_DATA}/scene/common/textures/placeholder.png"; + + const char* _loggerCat = "ProjectionComponent"; +} + +namespace openspace { + +using ghoul::Dictionary; +using glm::ivec2; + +documentation::Documentation ProjectionComponent::Documentation() { + using namespace documentation; + return { + "Projection Component", + "newhorizons_projectioncomponent", + { + { + keyInstrument, + new StringAnnotationVerifier("A SPICE name of an instrument"), + "The instrument that is used to perform the projections", + Optional::No + }, + { + keyInstrumentFovy, + new DoubleVerifier, + "The field of view in degrees along the y axis", + Optional::No + }, + { + keyInstrumentAspect, + new DoubleVerifier, + "The aspect ratio of the instrument in relation between x and y axis", + Optional::No + }, + { + keyProjObserver, + new StringAnnotationVerifier("A SPICE name of the observing object"), + "The observer that is doing the projection. This has to be a valid SPICE " + "name or SPICE integer.", + Optional::No + }, + { + keyProjTarget, + new StringAnnotationVerifier("A SPICE name of the observed object"), + "The observed object that is projected on. This has to be a valid SPICE " + "name or SPICE integer.", + Optional::No + }, + { + keyProjAberration, + new StringInListVerifier({ + // from SpiceManager::AberrationCorrection::AberrationCorrection + "NONE", "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S" + }), + "The aberration correction that is supposed to be used for the " + "projection. The values for the correction correspond to the SPICE " + "definition as described in " + "ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html", + Optional::No + }, + { + keyPotentialTargets, + new StringListVerifier, + "The list of potential targets that are involved with the image " + "projection", + Optional::Yes + }, + { + keyNeedsTextureMapDilation, + new BoolVerifier, + "Determines whether a dilation step of the texture map has to be " + "performed after each projection. This is necessary if the texture of " + "the projected object is a texture map where the borders are not " + "touching. The default value is 'false'.", + Optional::Yes + }, + { + keyNeedsShadowing, + new BoolVerifier, + "Determines whether the object requires a self-shadowing algorithm. This " + "is necessary if the object is concave and might cast a shadow on itself " + "during presentation. The default value is 'false'.", + Optional::Yes + }, + { + keyTextureMapAspectRatio, + new DoubleVerifier, + "Sets the desired aspect ratio of the projected texture. This might be " + "necessary as planets usually have 2x1 aspect ratios, whereas this does " + "not hold for non-planet objects (comets, asteroids, etc). The default " + "value is '1.0'.", + Optional::Yes + } + + } + }; +} + +ProjectionComponent::ProjectionComponent() + : properties::PropertyOwner("ProjectionComponent") + , _performProjection("performProjection", "Perform Projections", true) + , _clearAllProjections("clearAllProjections", "Clear Projections", false) + , _projectionFading("projectionFading", "Projection Fading", 1.f, 0.f, 1.f) + , _textureSize("textureSize", "Texture Size", ivec2(16), ivec2(16), ivec2(32768)) + , _applyTextureSize("applyTextureSize", "Apply Texture Size") + , _textureSizeDirty(false) + , _projectionTexture(nullptr) +{ + _shadowing.isEnabled = false; + _dilation.isEnabled = false; + + addProperty(_performProjection); + addProperty(_clearAllProjections); + addProperty(_projectionFading); + + addProperty(_textureSize); + addProperty(_applyTextureSize); + _applyTextureSize.onChange([this]() { _textureSizeDirty = true; }); +} + +void ProjectionComponent::initialize(const ghoul::Dictionary& dictionary) { + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "ProjectionComponent" + ); + _instrumentID = dictionary.value(keyInstrument); + _projectorID = dictionary.value(keyProjObserver); + _projecteeID = dictionary.value(keyProjTarget); + _fovy = static_cast(dictionary.value(keyInstrumentFovy)); + _aspectRatio = static_cast(dictionary.value(keyInstrumentAspect)); + + _aberration = SpiceManager::AberrationCorrection( + dictionary.value(keyProjAberration) + ); + + if (dictionary.hasKeyAndValue(keyPotentialTargets)) { + ghoul::Dictionary potentialTargets = dictionary.value( + keyPotentialTargets + ); + + _potentialTargets.reserve(potentialTargets.size()); + for (int i = 1; i <= potentialTargets.size(); ++i) { + _potentialTargets.emplace_back( + potentialTargets.value(std::to_string(i)) + ); + } + } + + if (dictionary.hasKeyAndValue(keyNeedsTextureMapDilation)) { + _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation); + } + + if (dictionary.hasKeyAndValue(keyNeedsShadowing)) { + _shadowing.isEnabled = dictionary.value(keyNeedsShadowing); + } + + _projectionTextureAspectRatio = 1.f; + if (dictionary.hasKeyAndValue(keyTextureMapAspectRatio)) { + _projectionTextureAspectRatio = + static_cast(dictionary.value(keyTextureMapAspectRatio)); + } + + std::string name; + dictionary.getValue(SceneGraphNode::KeyName, name); + + std::vector parsers; + + std::string sequenceSource; + std::string sequenceType; + bool foundSequence = dictionary.getValue(keySequenceDir, sequenceSource); + if (foundSequence) { + sequenceSource = absPath(sequenceSource); + + dictionary.getValue(keySequenceType, sequenceType); + //Important: client must define translation-list in mod file IFF playbook + if (dictionary.hasKey(keyTranslation)) { + ghoul::Dictionary translationDictionary; + //get translation dictionary + dictionary.getValue(keyTranslation, translationDictionary); + + if (sequenceType == sequenceTypePlaybook) { + parsers.push_back(new HongKangParser( + name, + sequenceSource, + _projectorID, + translationDictionary, + _potentialTargets)); + } + else if (sequenceType == sequenceTypeImage) { + parsers.push_back(new LabelParser( + name, + sequenceSource, + translationDictionary)); + } + else if (sequenceType == sequenceTypeHybrid) { + //first read labels + parsers.push_back(new LabelParser( + name, + sequenceSource, + translationDictionary)); + + std::string _eventFile; + bool foundEventFile = dictionary.getValue("EventFile", _eventFile); + if (foundEventFile) { + //then read playbook + _eventFile = absPath(_eventFile); + parsers.push_back(new HongKangParser( + name, + _eventFile, + _projectorID, + translationDictionary, + _potentialTargets)); + } + else { + LWARNING("No eventfile has been provided, please check modfiles"); + } + } + else if (sequenceType == sequenceTypeInstrumentTimes) { + parsers.push_back(new InstrumentTimesParser( + name, + sequenceSource, + translationDictionary)); + } + + for (SequenceParser* parser : parsers) { + openspace::ImageSequencer::ref().runSequenceParser(parser); + delete parser; + } + } + else { + LWARNING("No playbook translation provided, please make sure all spice calls match playbook!"); + } + } +} + +bool ProjectionComponent::initializeGL() { + int maxSize = OpenGLCap.max2DTextureSize(); + glm::ivec2 size; + + if (_projectionTextureAspectRatio > 1.f) { + size.x = maxSize; + size.y = static_cast(maxSize / _projectionTextureAspectRatio); + } + else { + size.x = static_cast(maxSize * _projectionTextureAspectRatio); + size.y = maxSize; + } + + _textureSize.setMaxValue(size); + _textureSize = size / 2; + + // We only want to use half the resolution per default: + size /= 2; + + bool success = generateProjectionLayerTexture(size); + success &= generateDepthTexture(size); + success &= auxiliaryRendertarget(); + success &= depthRendertarget(); + + using std::unique_ptr; + using ghoul::opengl::Texture; + using ghoul::io::TextureReader; + + unique_ptr texture = TextureReader::ref().loadTexture(absPath(placeholderFile)); + if (texture) { + texture->uploadTexture(); + // TODO: AnisotropicMipMap crashes on ATI cards ---abock + //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + texture->setFilter(Texture::FilterMode::Linear); + texture->setWrapping(Texture::WrappingMode::ClampToBorder); + } + _placeholderTexture = std::move(texture); + + if (_dilation.isEnabled) { + _dilation.program = ghoul::opengl::ProgramObject::Build( + "Dilation", + "${MODULE_NEWHORIZONS}/shaders/dilation_vs.glsl", + "${MODULE_NEWHORIZONS}/shaders/dilation_fs.glsl" + ); + + const GLfloat plane[] = { + -1, -1, + 1, 1, + -1, 1, + -1, -1, + 1, -1, + 1, 1, + }; + + glGenVertexArrays(1, &_dilation.vao); + glGenBuffers(1, &_dilation.vbo); + + glBindVertexArray(_dilation.vao); + glBindBuffer(GL_ARRAY_BUFFER, _dilation.vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(plane), plane, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer( + 0, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(GLfloat) * 2, + reinterpret_cast(0) + ); + + glBindVertexArray(0); + } + + return success; +} + +bool ProjectionComponent::deinitialize() { + _projectionTexture = nullptr; + + glDeleteFramebuffers(1, &_fboID); + + if (_dilation.isEnabled) { + glDeleteFramebuffers(1, &_dilation.fbo); + glDeleteVertexArrays(1, &_dilation.vao); + glDeleteBuffers(1, &_dilation.vbo); + + _dilation.program = nullptr; + _dilation.texture = nullptr; + } + + return true; +} + +bool ProjectionComponent::isReady() const { + return (_projectionTexture != nullptr); +} + +void ProjectionComponent::imageProjectBegin() { + // keep handle to the current bound FBO + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + + if (_textureSizeDirty) { + LDEBUG("Changing texture size to " << std::to_string(_textureSize)); + + // If the texture size has changed, we have to allocate new memory and copy + // the image texture to the new target + + using ghoul::opengl::Texture; + using ghoul::opengl::FramebufferObject; + + // Make a copy of the old textures + std::unique_ptr oldProjectionTexture = std::move(_projectionTexture); + std::unique_ptr oldDilationStencil = std::move(_dilation.stencilTexture); + std::unique_ptr oldDilationTexture = std::move(_dilation.texture); + std::unique_ptr oldDepthTexture = std::move(_shadowing.texture); + + // Generate the new textures + generateProjectionLayerTexture(_textureSize); + + if (_shadowing.isEnabled) { + generateDepthTexture(_textureSize); + } + + auto copyFramebuffers = [](Texture* src, Texture* dst, const std::string& msg) { + glFramebufferTexture( + GL_READ_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + *src, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Read Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glFramebufferTexture( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + *dst, + 0 + ); + + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Draw Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glBlitFramebuffer( + 0, 0, + src->dimensions().x, src->dimensions().y, + 0, 0, + dst->dimensions().x, dst->dimensions().y, + GL_COLOR_BUFFER_BIT, + GL_LINEAR + ); + }; + + auto copyDepthBuffer = [](Texture* src, Texture* dst, const std::string& msg) { + glFramebufferTexture( + GL_READ_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + *src, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Read Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glFramebufferTexture( + GL_DRAW_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + *dst, + 0 + ); + + status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + if (!FramebufferObject::errorChecking(status).empty()) { + LERROR( + "Draw Buffer (" << msg << "): " << + FramebufferObject::errorChecking(status) + ); + } + + glBlitFramebuffer( + 0, 0, + src->dimensions().x, src->dimensions().y, + 0, 0, + dst->dimensions().x, dst->dimensions().y, + GL_DEPTH_BUFFER_BIT, + GL_NEAREST + ); + }; + + GLuint fbos[2]; + glGenFramebuffers(2, fbos); + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); + + copyFramebuffers( + oldProjectionTexture.get(), + _projectionTexture.get(), + "Projection" + ); + + if (_dilation.isEnabled) { + copyFramebuffers( + oldDilationStencil.get(), + _dilation.stencilTexture.get(), + "Dilation Stencil" + ); + + copyFramebuffers( + oldDilationTexture.get(), + _dilation.texture.get(), + "Dilation Texture" + ); + } + + if (_shadowing.isEnabled) { + copyDepthBuffer( + oldDepthTexture.get(), + _shadowing.texture.get(), + "Shadowing" + ); + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glDeleteFramebuffers(2, fbos); + + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_projectionTexture, + 0 + ); + + if (_dilation.isEnabled) { + // We only need the stencil texture if we need to dilate + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_TEXTURE_2D, + *_dilation.stencilTexture, + 0 + ); + + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_dilation.texture, + 0 + ); + } + + if (_shadowing.isEnabled) { + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + *_shadowing.texture, + 0 + ); + } + + _textureSizeDirty = false; + } + + glGetIntegerv(GL_VIEWPORT, _viewport); + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + + glViewport( + 0, 0, + static_cast(_projectionTexture->width()), + static_cast(_projectionTexture->height()) + ); + + if (_dilation.isEnabled) { + GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; + glDrawBuffers(2, buffers); + } +} + +bool ProjectionComponent::needsShadowMap() const { + return _shadowing.isEnabled; +} + +ghoul::opengl::Texture& ProjectionComponent::depthTexture() { + return *_shadowing.texture; +} + +void ProjectionComponent::depthMapRenderBegin() { + ghoul_assert(_shadowing.isEnabled, "Shadowing is not enabled"); + + // keep handle to the current bound FBO + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_defaultFBO); + glGetIntegerv(GL_VIEWPORT, _viewport); + + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glEnable(GL_DEPTH_TEST); + + glViewport( + 0, 0, + static_cast(_shadowing.texture->width()), + static_cast(_shadowing.texture->height()) + ); + + glClear(GL_DEPTH_BUFFER_BIT); +} + +void ProjectionComponent::depthMapRenderEnd() { + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); + glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); +} + +void ProjectionComponent::imageProjectEnd() { + if (_dilation.isEnabled) { + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + + glDisable(GL_BLEND); + + ghoul::opengl::TextureUnit unit[2]; + unit[0].activate(); + _projectionTexture->bind(); + + unit[1].activate(); + _dilation.stencilTexture->bind(); + + _dilation.program->activate(); + _dilation.program->setUniform("tex", unit[0]); + _dilation.program->setUniform("stencil", unit[1]); + + glBindVertexArray(_dilation.vao); + glDrawArrays(GL_TRIANGLES, 0, 6); + + _dilation.program->deactivate(); + + glEnable(GL_BLEND); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _defaultFBO); + glViewport(_viewport[0], _viewport[1], _viewport[2], _viewport[3]); +} + +void ProjectionComponent::update() { + if (_dilation.isEnabled && _dilation.program->isDirty()) { + _dilation.program->rebuildFromFile(); + } +} + +bool ProjectionComponent::depthRendertarget() { + GLint defaultFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + // setup FBO + glGenFramebuffers(1, &_depthFboID); + glBindFramebuffer(GL_FRAMEBUFFER, _depthFboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + *_shadowing.texture, + 0); + + glDrawBuffer(GL_NONE); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) + return false; + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + return true; +} + +bool ProjectionComponent::auxiliaryRendertarget() { + bool completeSuccess = true; + + GLint defaultFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + + // setup FBO + glGenFramebuffers(1, &_fboID); + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_projectionTexture, + 0 + ); + // check FBO status + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Main Framebuffer incomplete"); + completeSuccess &= false; + } + + + if (_dilation.isEnabled) { + // We only need the stencil texture if we need to dilate + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_TEXTURE_2D, + *_dilation.stencilTexture, + 0 + ); + + // check FBO status + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Main Framebuffer incomplete"); + completeSuccess &= false; + } + + glGenFramebuffers(1, &_dilation.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + *_dilation.texture, + 0 + ); + + // check FBO status + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Dilation Framebuffer incomplete"); + completeSuccess &= false; + } + } + + // switch back to window-system-provided framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + + return completeSuccess; +} + +glm::mat4 ProjectionComponent::computeProjectorMatrix(const glm::vec3 loc, glm::dvec3 aim, + const glm::vec3 up, + const glm::dmat3& instrumentMatrix, + float fieldOfViewY, + float aspectRatio, + float nearPlane, float farPlane, + glm::vec3& boreSight) +{ + + //rotate boresight into correct alignment + boreSight = instrumentMatrix*aim; + glm::vec3 uptmp(instrumentMatrix*glm::dvec3(up)); + + // create view matrix + glm::vec3 e3 = glm::normalize(-boreSight); + glm::vec3 e1 = glm::normalize(glm::cross(uptmp, e3)); + glm::vec3 e2 = glm::normalize(glm::cross(e3, e1)); + + glm::mat4 projViewMatrix = glm::mat4(e1.x, e2.x, e3.x, 0.f, + e1.y, e2.y, e3.y, 0.f, + e1.z, e2.z, e3.z, 0.f, + glm::dot(e1, -loc), glm::dot(e2, -loc), glm::dot(e3, -loc), 1.f); + // create perspective projection matrix + glm::mat4 projProjectionMatrix = glm::perspective(glm::radians(fieldOfViewY), aspectRatio, nearPlane, farPlane); + + return projProjectionMatrix*projViewMatrix; +} + +bool ProjectionComponent::doesPerformProjection() const { + return _performProjection; +} + +bool ProjectionComponent::needsClearProjection() const { + return _clearAllProjections; +} + +float ProjectionComponent::projectionFading() const { + return _projectionFading; +} + +ghoul::opengl::Texture& ProjectionComponent::projectionTexture() const { + if (_dilation.isEnabled) { + return *_dilation.texture; + } + else { + return *_projectionTexture; + } +} + +std::string ProjectionComponent::projectorId() const { + return _projectorID; +} + +std::string ProjectionComponent::projecteeId() const { + return _projecteeID; +} + +std::string ProjectionComponent::instrumentId() const { + return _instrumentID; +} + +SpiceManager::AberrationCorrection ProjectionComponent::aberration() const { + return _aberration; +} + +float ProjectionComponent::fieldOfViewY() const { + return _fovy; +} + +float ProjectionComponent::aspectRatio() const { + return _aspectRatio; +} + +void ProjectionComponent::clearAllProjections() { + // keep handle to the current bound FBO + GLint defaultFBO; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO); + + GLint m_viewport[4]; + glGetIntegerv(GL_VIEWPORT, m_viewport); + //counter = 0; + glViewport(0, 0, static_cast(_projectionTexture->width()), static_cast(_projectionTexture->height())); + + glBindFramebuffer(GL_FRAMEBUFFER, _fboID); + + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + + if (_dilation.isEnabled) { + glBindFramebuffer(GL_FRAMEBUFFER, _dilation.fbo); + glClear(GL_COLOR_BUFFER_BIT); + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + glViewport(m_viewport[0], m_viewport[1], + m_viewport[2], m_viewport[3]); + + _clearAllProjections = false; +} + +std::shared_ptr ProjectionComponent::loadProjectionTexture( + const std::string& texturePath, + bool isPlaceholder) +{ + using std::unique_ptr; + using ghoul::opengl::Texture; + using ghoul::io::TextureReader; + + + if (isPlaceholder) { + return _placeholderTexture; + } + + + unique_ptr texture = TextureReader::ref().loadTexture(absPath(texturePath)); + if (texture) { + if (texture->format() == Texture::Format::Red) + ghoul::opengl::convertTextureFormat(*texture, Texture::Format::RGB); + texture->uploadTexture(); + // TODO: AnisotropicMipMap crashes on ATI cards ---abock + //_textureProj->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + texture->setFilter(Texture::FilterMode::Linear); + texture->setWrapping(Texture::WrappingMode::ClampToBorder); + } + return std::move(texture); +} + +bool ProjectionComponent::generateProjectionLayerTexture(const ivec2& size) { + LINFO( + "Creating projection texture of size '" << size.x << ", " << size.y << "'" + ); + _projectionTexture = std::make_unique ( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::RGBA + ); + if (_projectionTexture) { + _projectionTexture->uploadTexture(); + //_projectionTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + + if (_dilation.isEnabled) { + _dilation.texture = std::make_unique( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::RGBA + ); + + if (_dilation.texture) { + _dilation.texture->uploadTexture(); + //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + + _dilation.stencilTexture = std::make_unique( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::Red, + // @TODO: Remove the static cast ---abock + static_cast(ghoul::opengl::Texture::Format::Red) + ); + + if (_dilation.stencilTexture) { + _dilation.stencilTexture->uploadTexture(); + //_dilation.texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + } + + + return _projectionTexture != nullptr; + +} + +bool ProjectionComponent::generateDepthTexture(const ivec2& size) { + LINFO( + "Creating depth texture of size '" << size.x << ", " << size.y << "'" + ); + + _shadowing.texture = std::make_unique( + glm::uvec3(size, 1), + ghoul::opengl::Texture::Format::DepthComponent, + GL_DEPTH_COMPONENT32F + ); + + if (_shadowing.texture) { + _shadowing.texture->uploadTexture(); + } + + return _shadowing.texture != nullptr; + +} + +} // namespace openspace diff --git a/modules/space/rendering/renderableplanet.cpp b/modules/space/rendering/renderableplanet.cpp index 70e196d223..2d05de4755 100644 --- a/modules/space/rendering/renderableplanet.cpp +++ b/modules/space/rendering/renderableplanet.cpp @@ -1,563 +1,563 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define _USE_MATH_DEFINES -#include - - -namespace { - const char* KeyGeometry = "Geometry"; - const char* KeyRadius = "Radius"; - const char* KeyColorTexture = "Textures.Color"; - const char* KeyNightTexture = "Textures.Night"; - const char* KeyHeightTexture = "Textures.Height"; - const char* KeyShading = "PerformShading"; - - - - static const std::string _loggerCat = "RenderablePlanet"; - - const char* keyFrame = "Frame"; - const char* keyShadowGroup = "Shadow_Group"; - const char* keyShadowSource = "Source"; - const char* keyShadowCaster = "Caster"; - const char* keyBody = "Body"; -} // namespace - -namespace openspace { - -documentation::Documentation RenderablePlanet::Documentation() { - using namespace documentation; - return { - "RenderablePlanet", - "space_renderable_planet", - { - { - KeyGeometry, - new ReferencingVerifier("space_geometry_planet"), - "Specifies the planet geometry that is used for this RenderablePlanet.", - Optional::No - }, - { - KeyRadius, - new DoubleVerifier, - "Specifies the radius of the planet. If this value is not specified, it " - "will try to query the SPICE library for radius values.", - Optional::Yes - }, - { - KeyColorTexture, - new StringVerifier, - "Specifies the color texture that is used for this RenderablePlanet.", - Optional::Yes - }, - { - KeyHeightTexture, - new StringVerifier, - "Specifies the height texture that is used for this RenderablePlanet.", - Optional::Yes - }, - { - KeyNightTexture, - new StringVerifier, - "Specifies the texture that is used for the night side of this " - "RenderablePlanet.", - Optional::Yes - }, - { - KeyShading, - new BoolVerifier, - "Specifies whether the planet should be rendered shaded by the Sun. If " - "this value is 'false', any existing night texture will not be used. " - "This value defaults to 'true'.", - Optional::Yes - } - } - }; -} - -RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) - : Renderable(dictionary) - , _colorTexturePath("colorTexture", "Color Texture") - , _nightTexturePath("nightTexture", "Night Texture") - , _heightMapTexturePath("heightMap", "Heightmap Texture") - , _programObject(nullptr) - , _texture(nullptr) - , _nightTexture(nullptr) - , _heightExaggeration("heightExaggeration", "Height Exaggeration", 1.f, 0.f, 10.f) - , _geometry(nullptr) - , _performShading("performShading", "Perform Shading", true) - , _alpha(1.f) - , _planetRadius(0.f) - , _hasNightTexture(false) - , _hasHeightTexture(false) - , _shadowEnabled(false) -{ - ghoul_precondition( - dictionary.hasKeyAndValue(SceneGraphNode::KeyName), - "RenderablePlanet needs the name to be specified" - ); - - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderablePlanet" - ); - - const std::string name = dictionary.value(SceneGraphNode::KeyName); - - ghoul::Dictionary geomDict = dictionary.value(KeyGeometry); - - if (dictionary.hasKey(KeyRadius)) { - // If the user specified a radius, we want to use this - _planetRadius = dictionary.value(KeyRadius); - } - else if (SpiceManager::ref().hasValue(name, "RADII") ) { - // If the user didn't specfify a radius, but Spice has a radius, we can use this - glm::dvec3 radius; - SpiceManager::ref().getValue(name, "RADII", radius); - radius *= 1000.0; // Spice gives radii in KM. - std::swap(radius[1], radius[2]); // z is equivalent to y in our coordinate system - geomDict.setValue(KeyRadius, radius); - - _planetRadius = (radius.x + radius.y + radius.z) / 3.0; - } - else { - LERRORC("RenderablePlanet", "Missing radius specification"); - } - - _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geomDict); - - if (dictionary.hasKey(KeyColorTexture)) { - _colorTexturePath = absPath(dictionary.value(KeyColorTexture)); - } - - if (dictionary.hasKey(KeyNightTexture)) { - _hasNightTexture = true; - _nightTexturePath = absPath(dictionary.value(KeyNightTexture)); - } - - if (dictionary.hasKey(KeyHeightTexture)) { - _hasHeightTexture = true; - _heightMapTexturePath = absPath(dictionary.value(KeyHeightTexture)); - } - - if (dictionary.hasKey(KeyShading)) { - _performShading = dictionary.value(KeyShading); - } - - addPropertySubOwner(_geometry.get()); - - auto loadTextureCallback = [this]() {loadTexture(); }; - addProperty(_colorTexturePath); - _colorTexturePath.onChange(loadTextureCallback); - - addProperty(_nightTexturePath); - _nightTexturePath.onChange(loadTextureCallback); - - addProperty(_heightMapTexturePath); - _heightMapTexturePath.onChange(loadTextureCallback); - - addProperty(_heightExaggeration); - addProperty(_performShading); - - // Shadow data: - ghoul::Dictionary shadowDictionary; - bool success = dictionary.getValue(keyShadowGroup, shadowDictionary); - bool disableShadows = false; - if (success) { - std::vector< std::pair > sourceArray; - unsigned int sourceCounter = 1; - while (success) { - std::string sourceName; - std::stringstream ss; - ss << keyShadowSource << sourceCounter << ".Name"; - success = shadowDictionary.getValue(ss.str(), sourceName); - if (success) { - float sourceRadius; - ss.str(std::string()); - ss << keyShadowSource << sourceCounter << ".Radius"; - success = shadowDictionary.getValue(ss.str(), sourceRadius); - if (success) { - sourceArray.push_back(std::pair< std::string, float>( - sourceName, sourceRadius)); - } - else { - LWARNING("No Radius value expecified for Shadow Source Name " - << sourceName << " from " << name - << " planet.\nDisabling shadows for this planet."); - disableShadows = true; - break; - } - } - sourceCounter++; - } - - if (!disableShadows && !sourceArray.empty()) { - success = true; - std::vector< std::pair > casterArray; - unsigned int casterCounter = 1; - while (success) { - std::string casterName; - std::stringstream ss; - ss << keyShadowCaster << casterCounter << ".Name"; - success = shadowDictionary.getValue(ss.str(), casterName); - if (success) { - float casterRadius; - ss.str(std::string()); - ss << keyShadowCaster << casterCounter << ".Radius"; - success = shadowDictionary.getValue(ss.str(), casterRadius); - if (success) { - casterArray.push_back(std::pair< std::string, float>( - casterName, casterRadius)); - } - else { - LWARNING("No Radius value expecified for Shadow Caster Name " - << casterName << " from " << name - << " planet.\nDisabling shadows for this planet."); - disableShadows = true; - break; - } - } - - casterCounter++; - } - - if (!disableShadows && (!sourceArray.empty() && !casterArray.empty())) { - for (const auto & source : sourceArray) - for (const auto & caster : casterArray) { - ShadowConf sc; - sc.source = source; - sc.caster = caster; - _shadowConfArray.push_back(sc); - } - _shadowEnabled = true; - } - } - } -} - -bool RenderablePlanet::initialize() { - RenderEngine& renderEngine = OsEng.renderEngine(); - - if (_programObject == nullptr && _shadowEnabled && _hasNightTexture) { - // shadow program - _programObject = renderEngine.buildRenderProgram( - "shadowNightProgram", - "${MODULE_SPACE}/shaders/shadow_nighttexture_vs.glsl", - "${MODULE_SPACE}/shaders/shadow_nighttexture_fs.glsl"); - } - else if (_programObject == nullptr && _shadowEnabled) { - // shadow program - _programObject = renderEngine.buildRenderProgram( - "shadowProgram", - "${MODULE_SPACE}/shaders/shadow_vs.glsl", - "${MODULE_SPACE}/shaders/shadow_fs.glsl"); - } - else if (_programObject == nullptr && _hasNightTexture) { - // Night texture program - _programObject = renderEngine.buildRenderProgram( - "nightTextureProgram", - "${MODULE_SPACE}/shaders/nighttexture_vs.glsl", - "${MODULE_SPACE}/shaders/nighttexture_fs.glsl"); - } - else if (_programObject == nullptr) { - // pscstandard - _programObject = renderEngine.buildRenderProgram( - "pscstandard", - "${MODULE_SPACE}/shaders/renderableplanet_vs.glsl", - "${MODULE_SPACE}/shaders/renderableplanet_fs.glsl"); - } - using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; - _programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); - _programObject->setIgnoreUniformLocationError(IgnoreError::Yes); - - _geometry->initialize(this); - - _programObject->deactivate(); - - loadTexture(); - - return isReady(); -} - -bool RenderablePlanet::deinitialize() { - if (_geometry) { - _geometry->deinitialize(); - _geometry = nullptr; - } - - RenderEngine& renderEngine = OsEng.renderEngine(); - if (_programObject) { - renderEngine.removeRenderProgram(_programObject); - _programObject = nullptr; - } - - _geometry = nullptr; - _texture = nullptr; - _nightTexture = nullptr; - - return true; -} - -bool RenderablePlanet::isReady() const { - bool ready = true; - ready &= (_programObject != nullptr); - ready &= (_texture != nullptr); - ready &= (_geometry != nullptr); - return ready; -} - -void RenderablePlanet::render(const RenderData& data) { - // activate shader - _programObject->activate(); - - glm::dmat4 modelTransform = - glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation - glm::dmat4(data.modelTransform.rotation) * // Spice rotation - glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); - - // scale the planet to appropriate size since the planet is a unit sphere - //glm::mat4 transform = glm::mat4(1); - - //earth needs to be rotated for that to work. - glm::dmat4 rot = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(1, 0, 0)); - glm::dmat4 roty = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(0, -1, 0)); - //glm::dmat4 rotProp = glm::rotate(glm::dmat4(1.0), glm::radians(static_cast(_rotation)), glm::dvec3(0, 1, 0)); - modelTransform = modelTransform * rot * roty /** rotProp*/; - - glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; - - _programObject->setUniform("transparency", _alpha); - _programObject->setUniform( - "modelViewProjectionTransform", - data.camera.projectionMatrix() * glm::mat4(modelViewTransform) - ); - _programObject->setUniform("ModelTransform", glm::mat4(modelTransform)); - - // Normal Transformation - glm::mat4 translateObjTrans = glm::translate(glm::mat4(1.0), data.position.vec3()); - glm::mat4 translateCamTrans = glm::translate(glm::mat4(1.0), -data.camera.position().vec3()); - float scaleFactor = data.camera.scaling().x * powf(10.0, data.camera.scaling().y); - glm::mat4 scaleCamTrans = glm::scale(glm::mat4(1.0), glm::vec3(scaleFactor)); - -// glm::mat4 ModelViewTrans = data.camera.viewMatrix() * scaleCamTrans * -// translateCamTrans * translateObjTrans * glm::mat4(modelTransform); - - setPscUniforms(*_programObject.get(), data.camera, data.position); - - _programObject->setUniform("_performShading", _performShading); - - _programObject->setUniform("_hasHeightMap", _hasHeightTexture); - _programObject->setUniform("_heightExaggeration", _heightExaggeration); - - // Bind texture - ghoul::opengl::TextureUnit dayUnit; - ghoul::opengl::TextureUnit nightUnit; - ghoul::opengl::TextureUnit heightUnit; - - - dayUnit.activate(); - _texture->bind(); - _programObject->setUniform("texture1", dayUnit); - - // Bind possible night texture - if (_hasNightTexture && _nightTexture) { - nightUnit.activate(); - _nightTexture->bind(); - _programObject->setUniform("nightTex", nightUnit); - } - - if (_hasHeightTexture && _heightMapTexture) { - heightUnit.activate(); - _heightMapTexture->bind(); - _programObject->setUniform("heightTex", heightUnit); - } - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - // TODO: Move Calculations to VIEW SPACE (precision problems avoidance...) - - double lt; - // Shadow calculations.. - if (!_shadowConfArray.empty()) { - std::vector shadowDataArray; - shadowDataArray.reserve(_shadowConfArray.size()); - - for (const auto & shadowConf : _shadowConfArray) { - // TO REMEMBER: all distances and lengths in world coordinates are in meters!!! We need to move this to view space... - // Getting source and caster: - glm::dvec3 sourcePos = SpiceManager::ref().targetPosition(shadowConf.source.first, "SUN", "GALACTIC", {}, _time, lt); - sourcePos *= 1000.0; // converting to meters - glm::dvec3 casterPos = SpiceManager::ref().targetPosition(shadowConf.caster.first, "SUN", "GALACTIC", {}, _time, lt); - casterPos *= 1000.0; // converting to meters - psc caster_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate(casterPos.x, casterPos.y, casterPos.z); - - - // First we determine if the caster is shadowing the current planet (all calculations in World Coordinates): - glm::vec3 planetCasterVec = (caster_pos - data.position).vec3(); - glm::vec3 sourceCasterVec = glm::vec3(casterPos - sourcePos); - float sc_length = glm::length(sourceCasterVec); - glm::vec3 planetCaster_proj = (glm::dot(planetCasterVec, sourceCasterVec) / (sc_length*sc_length)) * sourceCasterVec; - float d_test = glm::length(planetCasterVec - planetCaster_proj); - float xp_test = shadowConf.caster.second * sc_length / (shadowConf.source.second + shadowConf.caster.second); - float rp_test = shadowConf.caster.second * (glm::length(planetCaster_proj) + xp_test) / xp_test; - - double casterDistSun = glm::length(casterPos); - float planetDistSun = glm::length(data.position.vec3()); - - ShadowRenderingStruct shadowData; - shadowData.isShadowing = false; - - if (((d_test - rp_test) < _planetRadius) && - (casterDistSun < planetDistSun) ) { - // The current caster is shadowing the current planet - shadowData.isShadowing = true; - shadowData.rs = shadowConf.source.second; - shadowData.rc = shadowConf.caster.second; - shadowData.sourceCasterVec = sourceCasterVec; - shadowData.xp = xp_test; - shadowData.xu = shadowData.rc * sc_length / (shadowData.rs - shadowData.rc); - shadowData.casterPositionVec = glm::vec3(casterPos); - } - shadowDataArray.push_back(shadowData); - } - - const std::string uniformVarName("shadowDataArray["); - unsigned int counter = 0; - for (const auto & sd : shadowDataArray) { - std::stringstream ss; - ss << uniformVarName << counter << "].isShadowing"; - _programObject->setUniform(ss.str(), sd.isShadowing); - if (sd.isShadowing) { - ss.str(std::string()); - ss << uniformVarName << counter << "].xp"; - _programObject->setUniform(ss.str(), sd.xp); - ss.str(std::string()); - ss << uniformVarName << counter << "].xu"; - _programObject->setUniform(ss.str(), sd.xu); - /*ss.str(std::string()); - ss << uniformVarName << counter << "].rs"; - _programObject->setUniform(ss.str(), sd.rs);*/ - ss.str(std::string()); - ss << uniformVarName << counter << "].rc"; - _programObject->setUniform(ss.str(), sd.rc); - ss.str(std::string()); - ss << uniformVarName << counter << "].sourceCasterVec"; - _programObject->setUniform(ss.str(), sd.sourceCasterVec); - ss.str(std::string()); - ss << uniformVarName << counter << "].casterPositionVec"; - _programObject->setUniform(ss.str(), sd.casterPositionVec); - } - counter++; - } - } - - // render - _geometry->render(); - - // disable shader - _programObject->deactivate(); - -} - -void RenderablePlanet::update(const UpdateData& data) { - // set spice-orientation in accordance to timestamp - _stateMatrix = data.modelTransform.rotation; - //_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time); - _time = data.time.j2000Seconds(); -} - -void RenderablePlanet::loadTexture() { - _texture = nullptr; - if (_colorTexturePath.value() != "") { - _texture = ghoul::io::TextureReader::ref().loadTexture(absPath(_colorTexturePath)); - if (_texture) { - if (_texture->numberOfChannels() == 1) { - _texture->setSwizzleMask({ GL_RED, GL_RED, GL_RED, GL_RED }); - } - - LDEBUG("Loaded texture from '" << _colorTexturePath << "'"); - _texture->uploadTexture(); - - // Textures of planets looks much smoother with AnisotropicMipMap rather than linear - // TODO: AnisotropicMipMap crashes on ATI cards ---abock - //_texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - _texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - } - } - - if (_hasNightTexture) { - _nightTexture = nullptr; - if (_nightTexturePath.value() != "") { - _nightTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_nightTexturePath)); - if (_nightTexture) { - LDEBUG("Loaded texture from '" << _nightTexturePath << "'"); - _nightTexture->uploadTexture(); - _nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - } - } - - if (_hasHeightTexture) { - _heightMapTexture = nullptr; - if (_heightMapTexturePath.value() != "") { - _heightMapTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_heightMapTexturePath)); - if (_heightMapTexture) { - LDEBUG("Loaded texture from '" << _heightMapTexturePath << "'"); - _heightMapTexture->uploadTexture(); - _heightMapTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); - //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - } - } - } -} - -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define _USE_MATH_DEFINES +#include + + +namespace { + const char* KeyGeometry = "Geometry"; + const char* KeyRadius = "Radius"; + const char* KeyColorTexture = "Textures.Color"; + const char* KeyNightTexture = "Textures.Night"; + const char* KeyHeightTexture = "Textures.Height"; + const char* KeyShading = "PerformShading"; + + + + static const std::string _loggerCat = "RenderablePlanet"; + + const char* keyFrame = "Frame"; + const char* keyShadowGroup = "Shadow_Group"; + const char* keyShadowSource = "Source"; + const char* keyShadowCaster = "Caster"; + const char* keyBody = "Body"; +} // namespace + +namespace openspace { + +documentation::Documentation RenderablePlanet::Documentation() { + using namespace documentation; + return { + "RenderablePlanet", + "space_renderable_planet", + { + { + KeyGeometry, + new ReferencingVerifier("space_geometry_planet"), + "Specifies the planet geometry that is used for this RenderablePlanet.", + Optional::No + }, + { + KeyRadius, + new DoubleVerifier, + "Specifies the radius of the planet. If this value is not specified, it " + "will try to query the SPICE library for radius values.", + Optional::Yes + }, + { + KeyColorTexture, + new StringVerifier, + "Specifies the color texture that is used for this RenderablePlanet.", + Optional::Yes + }, + { + KeyHeightTexture, + new StringVerifier, + "Specifies the height texture that is used for this RenderablePlanet.", + Optional::Yes + }, + { + KeyNightTexture, + new StringVerifier, + "Specifies the texture that is used for the night side of this " + "RenderablePlanet.", + Optional::Yes + }, + { + KeyShading, + new BoolVerifier, + "Specifies whether the planet should be rendered shaded by the Sun. If " + "this value is 'false', any existing night texture will not be used. " + "This value defaults to 'true'.", + Optional::Yes + } + } + }; +} + +RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _colorTexturePath("colorTexture", "Color Texture") + , _nightTexturePath("nightTexture", "Night Texture") + , _heightMapTexturePath("heightMap", "Heightmap Texture") + , _programObject(nullptr) + , _texture(nullptr) + , _nightTexture(nullptr) + , _heightExaggeration("heightExaggeration", "Height Exaggeration", 1.f, 0.f, 10.f) + , _geometry(nullptr) + , _performShading("performShading", "Perform Shading", true) + , _alpha(1.f) + , _planetRadius(0.f) + , _hasNightTexture(false) + , _hasHeightTexture(false) + , _shadowEnabled(false) +{ + ghoul_precondition( + dictionary.hasKeyAndValue(SceneGraphNode::KeyName), + "RenderablePlanet needs the name to be specified" + ); + + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderablePlanet" + ); + + const std::string name = dictionary.value(SceneGraphNode::KeyName); + + ghoul::Dictionary geomDict = dictionary.value(KeyGeometry); + + if (dictionary.hasKey(KeyRadius)) { + // If the user specified a radius, we want to use this + _planetRadius = dictionary.value(KeyRadius); + } + else if (SpiceManager::ref().hasValue(name, "RADII") ) { + // If the user didn't specfify a radius, but Spice has a radius, we can use this + glm::dvec3 radius; + SpiceManager::ref().getValue(name, "RADII", radius); + radius *= 1000.0; // Spice gives radii in KM. + std::swap(radius[1], radius[2]); // z is equivalent to y in our coordinate system + geomDict.setValue(KeyRadius, radius); + + _planetRadius = (radius.x + radius.y + radius.z) / 3.0; + } + else { + LERRORC("RenderablePlanet", "Missing radius specification"); + } + + _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geomDict); + + if (dictionary.hasKey(KeyColorTexture)) { + _colorTexturePath = absPath(dictionary.value(KeyColorTexture)); + } + + if (dictionary.hasKey(KeyNightTexture)) { + _hasNightTexture = true; + _nightTexturePath = absPath(dictionary.value(KeyNightTexture)); + } + + if (dictionary.hasKey(KeyHeightTexture)) { + _hasHeightTexture = true; + _heightMapTexturePath = absPath(dictionary.value(KeyHeightTexture)); + } + + if (dictionary.hasKey(KeyShading)) { + _performShading = dictionary.value(KeyShading); + } + + addPropertySubOwner(_geometry.get()); + + auto loadTextureCallback = [this]() {loadTexture(); }; + addProperty(_colorTexturePath); + _colorTexturePath.onChange(loadTextureCallback); + + addProperty(_nightTexturePath); + _nightTexturePath.onChange(loadTextureCallback); + + addProperty(_heightMapTexturePath); + _heightMapTexturePath.onChange(loadTextureCallback); + + addProperty(_heightExaggeration); + addProperty(_performShading); + + // Shadow data: + ghoul::Dictionary shadowDictionary; + bool success = dictionary.getValue(keyShadowGroup, shadowDictionary); + bool disableShadows = false; + if (success) { + std::vector< std::pair > sourceArray; + unsigned int sourceCounter = 1; + while (success) { + std::string sourceName; + std::stringstream ss; + ss << keyShadowSource << sourceCounter << ".Name"; + success = shadowDictionary.getValue(ss.str(), sourceName); + if (success) { + float sourceRadius; + ss.str(std::string()); + ss << keyShadowSource << sourceCounter << ".Radius"; + success = shadowDictionary.getValue(ss.str(), sourceRadius); + if (success) { + sourceArray.push_back(std::pair< std::string, float>( + sourceName, sourceRadius)); + } + else { + LWARNING("No Radius value expecified for Shadow Source Name " + << sourceName << " from " << name + << " planet.\nDisabling shadows for this planet."); + disableShadows = true; + break; + } + } + sourceCounter++; + } + + if (!disableShadows && !sourceArray.empty()) { + success = true; + std::vector< std::pair > casterArray; + unsigned int casterCounter = 1; + while (success) { + std::string casterName; + std::stringstream ss; + ss << keyShadowCaster << casterCounter << ".Name"; + success = shadowDictionary.getValue(ss.str(), casterName); + if (success) { + float casterRadius; + ss.str(std::string()); + ss << keyShadowCaster << casterCounter << ".Radius"; + success = shadowDictionary.getValue(ss.str(), casterRadius); + if (success) { + casterArray.push_back(std::pair< std::string, float>( + casterName, casterRadius)); + } + else { + LWARNING("No Radius value expecified for Shadow Caster Name " + << casterName << " from " << name + << " planet.\nDisabling shadows for this planet."); + disableShadows = true; + break; + } + } + + casterCounter++; + } + + if (!disableShadows && (!sourceArray.empty() && !casterArray.empty())) { + for (const auto & source : sourceArray) + for (const auto & caster : casterArray) { + ShadowConf sc; + sc.source = source; + sc.caster = caster; + _shadowConfArray.push_back(sc); + } + _shadowEnabled = true; + } + } + } +} + +bool RenderablePlanet::initialize() { + RenderEngine& renderEngine = OsEng.renderEngine(); + + if (_programObject == nullptr && _shadowEnabled && _hasNightTexture) { + // shadow program + _programObject = renderEngine.buildRenderProgram( + "shadowNightProgram", + "${MODULE_SPACE}/shaders/shadow_nighttexture_vs.glsl", + "${MODULE_SPACE}/shaders/shadow_nighttexture_fs.glsl"); + } + else if (_programObject == nullptr && _shadowEnabled) { + // shadow program + _programObject = renderEngine.buildRenderProgram( + "shadowProgram", + "${MODULE_SPACE}/shaders/shadow_vs.glsl", + "${MODULE_SPACE}/shaders/shadow_fs.glsl"); + } + else if (_programObject == nullptr && _hasNightTexture) { + // Night texture program + _programObject = renderEngine.buildRenderProgram( + "nightTextureProgram", + "${MODULE_SPACE}/shaders/nighttexture_vs.glsl", + "${MODULE_SPACE}/shaders/nighttexture_fs.glsl"); + } + else if (_programObject == nullptr) { + // pscstandard + _programObject = renderEngine.buildRenderProgram( + "pscstandard", + "${MODULE_SPACE}/shaders/renderableplanet_vs.glsl", + "${MODULE_SPACE}/shaders/renderableplanet_fs.glsl"); + } + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + _programObject->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); + _programObject->setIgnoreUniformLocationError(IgnoreError::Yes); + + _geometry->initialize(this); + + _programObject->deactivate(); + + loadTexture(); + + return isReady(); +} + +bool RenderablePlanet::deinitialize() { + if (_geometry) { + _geometry->deinitialize(); + _geometry = nullptr; + } + + RenderEngine& renderEngine = OsEng.renderEngine(); + if (_programObject) { + renderEngine.removeRenderProgram(_programObject); + _programObject = nullptr; + } + + _geometry = nullptr; + _texture = nullptr; + _nightTexture = nullptr; + + return true; +} + +bool RenderablePlanet::isReady() const { + bool ready = true; + ready &= (_programObject != nullptr); + ready &= (_texture != nullptr); + ready &= (_geometry != nullptr); + return ready; +} + +void RenderablePlanet::render(const RenderData& data) { + // activate shader + _programObject->activate(); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * // Translation + glm::dmat4(data.modelTransform.rotation) * // Spice rotation + glm::dmat4(glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale))); + + // scale the planet to appropriate size since the planet is a unit sphere + //glm::mat4 transform = glm::mat4(1); + + //earth needs to be rotated for that to work. + glm::dmat4 rot = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(1, 0, 0)); + glm::dmat4 roty = glm::rotate(glm::dmat4(1.0), M_PI_2, glm::dvec3(0, -1, 0)); + //glm::dmat4 rotProp = glm::rotate(glm::dmat4(1.0), glm::radians(static_cast(_rotation)), glm::dvec3(0, 1, 0)); + modelTransform = modelTransform * rot * roty /** rotProp*/; + + glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + + _programObject->setUniform("transparency", _alpha); + _programObject->setUniform( + "modelViewProjectionTransform", + data.camera.projectionMatrix() * glm::mat4(modelViewTransform) + ); + _programObject->setUniform("ModelTransform", glm::mat4(modelTransform)); + + // Normal Transformation + glm::mat4 translateObjTrans = glm::translate(glm::mat4(1.0), data.position.vec3()); + glm::mat4 translateCamTrans = glm::translate(glm::mat4(1.0), -data.camera.position().vec3()); + float scaleFactor = data.camera.scaling().x * powf(10.0, data.camera.scaling().y); + glm::mat4 scaleCamTrans = glm::scale(glm::mat4(1.0), glm::vec3(scaleFactor)); + +// glm::mat4 ModelViewTrans = data.camera.viewMatrix() * scaleCamTrans * +// translateCamTrans * translateObjTrans * glm::mat4(modelTransform); + + setPscUniforms(*_programObject.get(), data.camera, data.position); + + _programObject->setUniform("_performShading", _performShading); + + _programObject->setUniform("_hasHeightMap", _hasHeightTexture); + _programObject->setUniform("_heightExaggeration", _heightExaggeration); + + // Bind texture + ghoul::opengl::TextureUnit dayUnit; + ghoul::opengl::TextureUnit nightUnit; + ghoul::opengl::TextureUnit heightUnit; + + + dayUnit.activate(); + _texture->bind(); + _programObject->setUniform("texture1", dayUnit); + + // Bind possible night texture + if (_hasNightTexture && _nightTexture) { + nightUnit.activate(); + _nightTexture->bind(); + _programObject->setUniform("nightTex", nightUnit); + } + + if (_hasHeightTexture && _heightMapTexture) { + heightUnit.activate(); + _heightMapTexture->bind(); + _programObject->setUniform("heightTex", heightUnit); + } + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + // TODO: Move Calculations to VIEW SPACE (precision problems avoidance...) + + double lt; + // Shadow calculations.. + if (!_shadowConfArray.empty()) { + std::vector shadowDataArray; + shadowDataArray.reserve(_shadowConfArray.size()); + + for (const auto & shadowConf : _shadowConfArray) { + // TO REMEMBER: all distances and lengths in world coordinates are in meters!!! We need to move this to view space... + // Getting source and caster: + glm::dvec3 sourcePos = SpiceManager::ref().targetPosition(shadowConf.source.first, "SUN", "GALACTIC", {}, _time, lt); + sourcePos *= 1000.0; // converting to meters + glm::dvec3 casterPos = SpiceManager::ref().targetPosition(shadowConf.caster.first, "SUN", "GALACTIC", {}, _time, lt); + casterPos *= 1000.0; // converting to meters + psc caster_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate(casterPos.x, casterPos.y, casterPos.z); + + + // First we determine if the caster is shadowing the current planet (all calculations in World Coordinates): + glm::vec3 planetCasterVec = (caster_pos - data.position).vec3(); + glm::vec3 sourceCasterVec = glm::vec3(casterPos - sourcePos); + float sc_length = glm::length(sourceCasterVec); + glm::vec3 planetCaster_proj = (glm::dot(planetCasterVec, sourceCasterVec) / (sc_length*sc_length)) * sourceCasterVec; + float d_test = glm::length(planetCasterVec - planetCaster_proj); + float xp_test = shadowConf.caster.second * sc_length / (shadowConf.source.second + shadowConf.caster.second); + float rp_test = shadowConf.caster.second * (glm::length(planetCaster_proj) + xp_test) / xp_test; + + double casterDistSun = glm::length(casterPos); + float planetDistSun = glm::length(data.position.vec3()); + + ShadowRenderingStruct shadowData; + shadowData.isShadowing = false; + + if (((d_test - rp_test) < _planetRadius) && + (casterDistSun < planetDistSun) ) { + // The current caster is shadowing the current planet + shadowData.isShadowing = true; + shadowData.rs = shadowConf.source.second; + shadowData.rc = shadowConf.caster.second; + shadowData.sourceCasterVec = sourceCasterVec; + shadowData.xp = xp_test; + shadowData.xu = shadowData.rc * sc_length / (shadowData.rs - shadowData.rc); + shadowData.casterPositionVec = glm::vec3(casterPos); + } + shadowDataArray.push_back(shadowData); + } + + const std::string uniformVarName("shadowDataArray["); + unsigned int counter = 0; + for (const auto & sd : shadowDataArray) { + std::stringstream ss; + ss << uniformVarName << counter << "].isShadowing"; + _programObject->setUniform(ss.str(), sd.isShadowing); + if (sd.isShadowing) { + ss.str(std::string()); + ss << uniformVarName << counter << "].xp"; + _programObject->setUniform(ss.str(), sd.xp); + ss.str(std::string()); + ss << uniformVarName << counter << "].xu"; + _programObject->setUniform(ss.str(), sd.xu); + /*ss.str(std::string()); + ss << uniformVarName << counter << "].rs"; + _programObject->setUniform(ss.str(), sd.rs);*/ + ss.str(std::string()); + ss << uniformVarName << counter << "].rc"; + _programObject->setUniform(ss.str(), sd.rc); + ss.str(std::string()); + ss << uniformVarName << counter << "].sourceCasterVec"; + _programObject->setUniform(ss.str(), sd.sourceCasterVec); + ss.str(std::string()); + ss << uniformVarName << counter << "].casterPositionVec"; + _programObject->setUniform(ss.str(), sd.casterPositionVec); + } + counter++; + } + } + + // render + _geometry->render(); + + // disable shader + _programObject->deactivate(); + +} + +void RenderablePlanet::update(const UpdateData& data) { + // set spice-orientation in accordance to timestamp + _stateMatrix = data.modelTransform.rotation; + //_stateMatrix = SpiceManager::ref().positionTransformMatrix(_frame, "GALACTIC", data.time); + _time = data.time.j2000Seconds(); +} + +void RenderablePlanet::loadTexture() { + _texture = nullptr; + if (_colorTexturePath.value() != "") { + _texture = ghoul::io::TextureReader::ref().loadTexture(absPath(_colorTexturePath)); + if (_texture) { + if (_texture->numberOfChannels() == 1) { + _texture->setSwizzleMask({ GL_RED, GL_RED, GL_RED, GL_RED }); + } + + LDEBUG("Loaded texture from '" << _colorTexturePath << "'"); + _texture->uploadTexture(); + + // Textures of planets looks much smoother with AnisotropicMipMap rather than linear + // TODO: AnisotropicMipMap crashes on ATI cards ---abock + //_texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + _texture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + } + } + + if (_hasNightTexture) { + _nightTexture = nullptr; + if (_nightTexturePath.value() != "") { + _nightTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_nightTexturePath)); + if (_nightTexture) { + LDEBUG("Loaded texture from '" << _nightTexturePath << "'"); + _nightTexture->uploadTexture(); + _nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + } + } + + if (_hasHeightTexture) { + _heightMapTexture = nullptr; + if (_heightMapTexturePath.value() != "") { + _heightMapTexture = ghoul::io::TextureReader::ref().loadTexture(absPath(_heightMapTexturePath)); + if (_heightMapTexture) { + LDEBUG("Loaded texture from '" << _heightMapTexturePath << "'"); + _heightMapTexture->uploadTexture(); + _heightMapTexture->setFilter(ghoul::opengl::Texture::FilterMode::Linear); + //_nightTexture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + } + } + } +} + +} // namespace openspace diff --git a/modules/volume/rawvolumewriter.h b/modules/volume/rawvolumewriter.h index ec0cdf28f1..2dd3b19012 100644 --- a/modules/volume/rawvolumewriter.h +++ b/modules/volume/rawvolumewriter.h @@ -1,57 +1,57 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ -#define __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ - -#include -#include -#include - -namespace openspace { - -template -class RawVolumeWriter { -public: - RawVolumeWriter(std::string path, size_t bufferSize = 1024); - void setPath(const std::string& path); - glm::uvec3 dimensions() const; - void setDimensions(const glm::uvec3& dimensions); - void write(const std::function& fn, - const std::function& onProgress = [](float t) {}); - void write(const RawVolume& volume); - - size_t coordsToIndex(const glm::uvec3& coords) const; - glm::ivec3 indexToCoords(size_t linear) const; -private: - glm::ivec3 _dimensions; - std::string _path; - size_t _bufferSize; -}; - -} // namespace openspace - -#include "rawvolumewriter.inl"; - -#endif // __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ +#define __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ + +#include +#include +#include + +namespace openspace { + +template +class RawVolumeWriter { +public: + RawVolumeWriter(std::string path, size_t bufferSize = 1024); + void setPath(const std::string& path); + glm::uvec3 dimensions() const; + void setDimensions(const glm::uvec3& dimensions); + void write(const std::function& fn, + const std::function& onProgress = [](float t) {}); + void write(const RawVolume& volume); + + size_t coordsToIndex(const glm::uvec3& coords) const; + glm::ivec3 indexToCoords(size_t linear) const; +private: + glm::ivec3 _dimensions; + std::string _path; + size_t _bufferSize; +}; + +} // namespace openspace + +#include "rawvolumewriter.inl" + +#endif // __OPENSPACE_MODULE_VOLUME___RAWVOLUMEWRITER___H__ diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 5e98081847..5a88b5092f 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1,1446 +1,1446 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if defined(_MSC_VER) && defined(OPENSPACE_ENABLE_VLD) -#include -#endif - -#ifdef WIN32 -#include -#endif - -#include "openspaceengine_lua.inl" - -using namespace openspace::scripting; -using namespace ghoul::filesystem; -using namespace ghoul::logging; -using namespace ghoul::cmdparser; - -namespace { - const char* _loggerCat = "OpenSpaceEngine"; - const char* SgctDefaultConfigFile = "${SGCT}/single.xml"; - - const char* SgctConfigArgumentCommand = "-config"; - - const char* PreInitializeFunction = "preInitialization"; - const char* PostInitializationFunction = "postInitialization"; - - const int CacheVersion = 1; - const int DownloadVersion = 1; - - const glm::ivec3 FontAtlasSize{ 1536, 1536, 1 }; - - - struct { - std::string configurationName; - std::string sgctConfigurationName; - std::string sceneName; - std::string cacheFolder; - } commandlineArgumentPlaceholders; -} - -namespace openspace { - -namespace properties { - class Property; -} - -class Scene; - -OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; - -OpenSpaceEngine::OpenSpaceEngine(std::string programName, - std::unique_ptr windowWrapper) - : _configurationManager(new ConfigurationManager) - , _sceneManager(new SceneManager) - , _downloadManager(nullptr) - , _console(new LuaConsole) - , _moduleEngine(new ModuleEngine) - , _networkEngine(new NetworkEngine) - , _parallelConnection(new ParallelConnection) - , _renderEngine(new RenderEngine) - , _settingsEngine(new SettingsEngine) - , _syncEngine(std::make_unique(4096)) - , _timeManager(new TimeManager) - , _windowWrapper(std::move(windowWrapper)) - , _commandlineParser(new ghoul::cmdparser::CommandlineParser( - programName, ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes - )) - , _interactionHandler(new interaction::InteractionHandler) - , _scriptEngine(new scripting::ScriptEngine) - , _scriptScheduler(new scripting::ScriptScheduler) - , _virtualPropertyManager(new VirtualPropertyManager) - , _globalPropertyNamespace(new properties::PropertyOwner("")) - , _scheduledSceneSwitch(false) - , _scenePath("") - , _runTime(0.0) - , _shutdown({false, 0.f, 0.f}) - , _isFirstRenderingFirstFrame(true) -{ - _interactionHandler->setPropertyOwner(_globalPropertyNamespace.get()); - - // New property subowners also have to be added to the OnScreenGuiModule callback! - _globalPropertyNamespace->addPropertySubOwner(_interactionHandler.get()); - _globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get()); - _globalPropertyNamespace->addPropertySubOwner(_renderEngine.get()); - _globalPropertyNamespace->addPropertySubOwner(_windowWrapper.get()); - _globalPropertyNamespace->addPropertySubOwner(_parallelConnection.get()); - _globalPropertyNamespace->addPropertySubOwner(_console.get()); - - FactoryManager::initialize(); - FactoryManager::ref().addFactory( - std::make_unique>(), - "Renderable" - ); - FactoryManager::ref().addFactory( - std::make_unique>(), - "Translation" - ); - FactoryManager::ref().addFactory( - std::make_unique>(), - "Rotation" - ); - FactoryManager::ref().addFactory( - std::make_unique>(), - "Scale" - ); - FactoryManager::ref().addFactory( - std::make_unique>(), - "Task" - ); - - SpiceManager::initialize(); - TransformationManager::initialize(); -} - -OpenSpaceEngine& OpenSpaceEngine::ref() { - ghoul_assert(_engine, "OpenSpaceEngine not created"); - return *_engine; -} - -bool OpenSpaceEngine::isCreated() { - return _engine != nullptr; -} - -void OpenSpaceEngine::create(int argc, char** argv, - std::unique_ptr windowWrapper, - std::vector& sgctArguments, bool& requestClose) -{ - ghoul_assert(!_engine, "OpenSpaceEngine was already created"); - ghoul_assert(windowWrapper != nullptr, "No Window Wrapper was provided"); - - requestClose = false; - - ghoul::initialize(); - - // Initialize the LogManager and add the console log as this will be used every time - // and we need a fall back if something goes wrong between here and when we add the - // logs from the configuration file. If the user requested as specific loglevel in the - // configuration file, we will deinitialize this LogManager and reinitialize it later - // with the correct LogLevel - LogManager::initialize( - LogLevel::Debug, - ghoul::logging::LogManager::ImmediateFlush::Yes - ); - LogMgr.addLog(std::make_unique()); - - LDEBUG("Initialize FileSystem"); - -#ifdef __APPLE__ - ghoul::filesystem::File app(argv[0]); - std::string dirName = app.directoryName(); - LINFO("Setting starting directory to '" << dirName << "'"); - FileSys.setCurrentDirectory(dirName); -#endif - - // Sanity check of values - if (argc < 1 || argv == nullptr) { - throw ghoul::RuntimeError( - "No arguments were passed to this function", - "OpenSpaceEngine" - ); - } - - // Create other objects - LDEBUG("Creating OpenSpaceEngine"); - _engine = new OpenSpaceEngine(std::string(argv[0]), std::move(windowWrapper)); - - // Query modules for commandline arguments - _engine->gatherCommandlineArguments(); - - // Parse commandline arguments - std::vector args(argv, argv + argc); - std::shared_ptr> arguments = - _engine->_commandlineParser->setCommandLine(args); - - bool showHelp = _engine->_commandlineParser->execute(); - if (showHelp) { - _engine->_commandlineParser->displayHelp(); - requestClose = true; - return; - } - sgctArguments = *arguments; - - // Find configuration - std::string configurationFilePath = commandlineArgumentPlaceholders.configurationName; - if (configurationFilePath.empty()) { - LDEBUG("Finding configuration"); - configurationFilePath = - ConfigurationManager::findConfiguration(configurationFilePath); - } - configurationFilePath = absPath(configurationFilePath); - - if (!FileSys.fileExists(configurationFilePath)) { - throw ghoul::FileNotFoundError( - "Configuration file '" + configurationFilePath + "' not found" - ); - } - LINFO("Configuration Path: '" << configurationFilePath << "'"); - - // Loading configuration from disk - LDEBUG("Loading configuration from disk"); - try { - _engine->configurationManager().loadFromFile(configurationFilePath); - } - catch (const documentation::SpecificationError& e) { - LFATAL("Loading of configuration file '" << configurationFilePath << "' failed"); - for (const documentation::TestResult::Offense& o : e.result.offenses) { - LERRORC(o.offender, std::to_string(o.reason)); - } - for (const documentation::TestResult::Warning& w : e.result.warnings) { - LWARNINGC(w.offender, std::to_string(w.reason)); - } - throw; - } - catch (const ghoul::RuntimeError&) { - LFATAL("Loading of configuration file '" << configurationFilePath << "' failed"); - throw; - } - - const bool hasCacheCommandline = !commandlineArgumentPlaceholders.cacheFolder.empty(); - const bool hasCacheConfiguration = _engine->configurationManager().hasKeyAndValue( - ConfigurationManager::KeyPerSceneCache - ); - std::string cacheFolder = absPath("${CACHE}"); - if (hasCacheCommandline) { - cacheFolder = commandlineArgumentPlaceholders.cacheFolder; - // @CLEANUP: Why is this commented out? ---abock - //FileSys.registerPathToken( - // "${CACHE}", - // commandlineArgumentPlaceholders.cacheFolder, - // ghoul::filesystem::FileSystem::Override::Yes - //); - } - if (hasCacheConfiguration) { - std::string scene = _engine->configurationManager().value( - ConfigurationManager::KeyConfigScene - ); - cacheFolder += "-" + ghoul::filesystem::File(scene).baseName(); - } - - if (hasCacheCommandline || hasCacheConfiguration) { - LINFO("Old cache: " << absPath("${CACHE}")); - LINFO("New cache: " << cacheFolder); - FileSys.registerPathToken( - "${CACHE}", - cacheFolder, - ghoul::filesystem::FileSystem::Override::Yes - ); - } - - // Initialize the requested logs from the configuration file - _engine->configureLogging(); - - LINFOC("OpenSpace Version", - OPENSPACE_VERSION_MAJOR << "." << - OPENSPACE_VERSION_MINOR << "." << - OPENSPACE_VERSION_PATCH << - " (" << OPENSPACE_VERSION_STRING << ")" - ); - - // Create directories that doesn't exist - auto tokens = FileSys.tokens(); - for (const std::string& token : tokens) { - if (!FileSys.directoryExists(token)) { - std::string p = absPath(token); - LDEBUG("Directory '" << p << "' does not exist, creating."); - FileSys.createDirectory(p, ghoul::filesystem::FileSystem::Recursive::Yes); - } - } - - // Register modules - _engine->_moduleEngine->initialize(); - - // After registering the modules, the documentations for the available classes - // can be added as well - for (OpenSpaceModule* m : _engine->_moduleEngine->modules()) { - for (const documentation::Documentation& doc : m->documentations()) { - DocEng.addDocumentation(doc); - } - } - - // Create the cachemanager - FileSys.createCacheManager( - absPath("${" + ConfigurationManager::KeyCache + "}"), CacheVersion - ); - - // Register the provided shader directories - ghoul::opengl::ShaderPreprocessor::addIncludePath(absPath("${SHADERS}")); - - // Determining SGCT configuration file - LDEBUG("Determining SGCT configuration file"); - std::string sgctConfigurationPath = SgctDefaultConfigFile; - _engine->configurationManager().getValue( - ConfigurationManager::KeyConfigSgct, sgctConfigurationPath); - - if (!commandlineArgumentPlaceholders.sgctConfigurationName.empty()) { - LDEBUG("Overwriting SGCT configuration file with commandline argument: " << - commandlineArgumentPlaceholders.sgctConfigurationName); - sgctConfigurationPath = commandlineArgumentPlaceholders.sgctConfigurationName; - } - - // Prepend the outgoing sgctArguments with the program name - // as well as the configuration file that sgct is supposed to use - sgctArguments.insert(sgctArguments.begin(), argv[0]); - sgctArguments.insert(sgctArguments.begin() + 1, SgctConfigArgumentCommand); - sgctArguments.insert(sgctArguments.begin() + 2, absPath(sgctConfigurationPath)); -} - -void OpenSpaceEngine::destroy() { - if (_engine->parallelConnection().status() != ParallelConnection::Status::Disconnected) { - _engine->parallelConnection().signalDisconnect(); - } - - LTRACE("OpenSpaceEngine::destroy(begin)"); - for (const auto& func : _engine->_moduleCallbacks.deinitializeGL) { - func(); - } - - for (const auto& func : _engine->_moduleCallbacks.deinitialize) { - func(); - } - - _engine->_syncEngine->removeSyncables(_engine->timeManager().getSyncables()); - _engine->_syncEngine->removeSyncables(_engine->_renderEngine->getSyncables()); - _engine->_syncEngine->removeSyncable(_engine->_scriptEngine.get()); - - _engine->_moduleEngine->deinitialize(); - _engine->_console->deinitialize(); - - _engine->_scriptEngine->deinitialize(); - _engine->_sceneManager->unloadAll(); - - delete _engine; - FactoryManager::deinitialize(); - SpiceManager::deinitialize(); - - ghoul::fontrendering::FontRenderer::deinitialize(); - - LogManager::deinitialize(); - - ghoul::deinitialize(); - LTRACE("OpenSpaceEngine::destroy(end)"); -} - -void OpenSpaceEngine::initialize() { - LTRACE("OpenSpaceEngine::initialize(begin)"); - - glbinding::Binding::useCurrentContext(); - glbinding::Binding::initialize(); - - // clear the screen so the user don't have to see old buffer contents from the - // graphics card - LDEBUG("Clearing all Windows"); - _windowWrapper->clearAllWindows(glm::vec4(0.f, 0.f, 0.f, 1.f)); - - LDEBUG("Adding system components"); - // Detect and log OpenCL and OpenGL versions and available devices - SysCap.addComponent( - std::make_unique() - ); - SysCap.addComponent( - std::make_unique() - ); - - // @BUG: This will call OpenGL functions, should it should be in the initializeGL - LDEBUG("Detecting capabilities"); - SysCap.detectCapabilities(); - - using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity; - Verbosity verbosity = Verbosity::Default; - if (configurationManager().hasKey(ConfigurationManager::KeyCapabilitiesVerbosity)) { - static const std::map VerbosityMap = { - { "None", Verbosity::None }, - { "Minimal", Verbosity::Minimal }, - { "Default", Verbosity::Default }, - { "Full", Verbosity::Full } - }; - - std::string v = configurationManager().value( - ConfigurationManager::KeyCapabilitiesVerbosity - ); - ghoul_assert( - VerbosityMap.find(v) != VerbosityMap.end(), - "Missing check for syscaps verbosity in openspace.cfg documentation" - ); - verbosity = VerbosityMap.find(v)->second; - } - SysCap.logCapabilities(verbosity); - - // Check the required OpenGL versions of the registered modules - ghoul::systemcapabilities::Version version = - _engine->_moduleEngine->requiredOpenGLVersion(); - LINFO("Required OpenGL version: " << std::to_string(version)); - - if (OpenGLCap.openGLVersion() < version) { - throw ghoul::RuntimeError( - "Module required higher OpenGL version than is supported", - "OpenSpaceEngine" - ); - } - - if (configurationManager().hasKey(ConfigurationManager::KeyDownloadRequestURL)) { - const std::string requestUrl = configurationManager().value( - ConfigurationManager::KeyDownloadRequestURL - ); - - _downloadManager = std::make_unique( - requestUrl, - DownloadVersion - ); - } - - // Register Lua script functions - LDEBUG("Registering Lua libraries"); - registerCoreClasses(*_scriptEngine); - - for (OpenSpaceModule* module : _moduleEngine->modules()) { - _scriptEngine->addLibrary(module->luaLibrary()); - } - - // TODO: Maybe move all scenegraph and renderengine stuff to initializeGL - scriptEngine().initialize(); - - writeDocumentation(); - - if (configurationManager().hasKey(ConfigurationManager::KeyShutdownCountdown)) { - _shutdown.waitTime = static_cast(configurationManager().value( - ConfigurationManager::KeyShutdownCountdown - )); - } - - if (!commandlineArgumentPlaceholders.sceneName.empty()) { - configurationManager().setValue( - ConfigurationManager::KeyConfigScene, - commandlineArgumentPlaceholders.sceneName - ); - } - - // Initialize the SettingsEngine - _settingsEngine->initialize(); - _settingsEngine->setModules(_moduleEngine->modules()); - - // Initialize the InteractionHandler - _interactionHandler->initialize(); - - // Load a light and a monospaced font - loadFonts(); - - std::string scenePath = ""; - configurationManager().getValue(ConfigurationManager::KeyConfigScene, scenePath); - - _renderEngine->initialize(); - - for (const auto& func : _moduleCallbacks.initialize) { - func(); - } - - scheduleLoadScene(scenePath); - - LTRACE("OpenSpaceEngine::initialize(end)"); - -} - -void OpenSpaceEngine::scheduleLoadScene(std::string scenePath) { - _scheduledSceneSwitch = true; - _scenePath = std::move(scenePath); -} - -void OpenSpaceEngine::loadScene(const std::string& scenePath) { - LTRACE("OpenSpaceEngine::loadScene(begin)"); - - windowWrapper().setBarrier(false); - windowWrapper().setSynchronization(false); - OnExit( - [this]() { - windowWrapper().setSynchronization(true); - windowWrapper().setBarrier(true); - } - ); - - // Run start up scripts - try { - runPreInitializationScripts(scenePath); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - - Scene* scene; - try { - scene = _sceneManager->loadScene(scenePath); - } catch (const ghoul::FileNotFoundError& e) { - LERRORC(e.component, e.message); - return; - } catch (const Scene::InvalidSceneError& e) { - LERRORC(e.component, e.message); - return; - } catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - return; - } - catch (const std::exception& e) { - LERROR(e.what()); - return; - } - catch (...) { - LERROR("Unknown error loading the scene"); - return; - } - - Scene* previousScene = _renderEngine->scene(); - if (previousScene) { - _syncEngine->removeSyncables(_timeManager->getSyncables()); - _syncEngine->removeSyncables(_renderEngine->getSyncables()); - _syncEngine->removeSyncable(_scriptEngine.get()); - - _renderEngine->setScene(nullptr); - _renderEngine->setCamera(nullptr); - _sceneManager->unloadScene(*previousScene); - } - - // Initialize the RenderEngine - _renderEngine->setScene(scene); - _renderEngine->setCamera(scene->camera()); - _renderEngine->setGlobalBlackOutFactor(0.0); - _renderEngine->startFading(1, 3.0); - - scene->initialize(); - _interactionHandler->setCamera(scene->camera()); - - try { - runPostInitializationScripts(scenePath); - } - catch (const ghoul::RuntimeError& e) { - LFATALC(e.component, e.message); - } - - // Write keyboard documentation. - if (configurationManager().hasKey(ConfigurationManager::KeyKeyboardShortcuts)) { - interactionHandler().writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyKeyboardShortcuts - )) - ); - } - - // If a PropertyDocumentationFile was specified, generate it now. - if (configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentation)) { - scene->writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyPropertyDocumentation - )) - ); - } - - _syncEngine->addSyncables(_timeManager->getSyncables()); - _syncEngine->addSyncables(_renderEngine->getSyncables()); - _syncEngine->addSyncable(_scriptEngine.get()); - - LTRACE("OpenSpaceEngine::loadScene(end)"); -} - -void OpenSpaceEngine::deinitialize() { - LTRACE("OpenSpaceEngine::deinitialize(begin)"); - - _interactionHandler->deinitialize(); - _renderEngine->deinitialize(); - - LTRACE("OpenSpaceEngine::deinitialize(end)"); -} - -void OpenSpaceEngine::writeDocumentation() { - // If a LuaDocumentationFile was specified, generate it now - if (configurationManager().hasKey(ConfigurationManager::KeyLuaDocumentation)) { - _scriptEngine->writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyLuaDocumentation - )) - ); - } - - // If a general documentation was specified, generate it now - if (configurationManager().hasKey(ConfigurationManager::KeyDocumentation)) { - DocEng.writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyDocumentation - )) - ); - } - - // If a factory documentation was specified, generate it now - if (configurationManager().hasKey(ConfigurationManager::KeyFactoryDocumentation)) { - FactoryManager::ref().writeDocumentation( - absPath(configurationManager().value( - ConfigurationManager::KeyFactoryDocumentation - )) - ); - } -} - -void OpenSpaceEngine::gatherCommandlineArguments() { - commandlineArgumentPlaceholders.configurationName = ""; - _commandlineParser->addCommand(std::make_unique>( - &commandlineArgumentPlaceholders.configurationName, "-config", "-c", - "Provides the path to the OpenSpace configuration file" - )); - - commandlineArgumentPlaceholders.sgctConfigurationName = ""; - _commandlineParser->addCommand(std::make_unique>( - &commandlineArgumentPlaceholders.sgctConfigurationName, "-sgct", "-s", - "Provides the path to the SGCT configuration file, overriding the value set in " - "the OpenSpace configuration file" - )); - - commandlineArgumentPlaceholders.sceneName = ""; - _commandlineParser->addCommand(std::make_unique>( - &commandlineArgumentPlaceholders.sceneName, "-scene", "", "Provides the path to " - "the scene file, overriding the value set in the OpenSpace configuration file" - )); - - commandlineArgumentPlaceholders.cacheFolder = ""; - _commandlineParser->addCommand(std::make_unique>( - &commandlineArgumentPlaceholders.cacheFolder, "-cacheDir", "", "Provides the " - "path to a cache file, overriding the value set in the OpenSpace configuration " - "file" - )); -} - -void OpenSpaceEngine::runPreInitializationScripts(const std::string& sceneDescription) { - // @CLEANUP: Move this into the scene loading? ---abock - LINFO("Running Initialization scripts"); - - ghoul::lua::LuaState state; - OsEng.scriptEngine().initializeLuaState(state); - - // First execute the script to get all global variables - ghoul::lua::runScriptFile(state, absPath(sceneDescription)); - - // Get the preinitialize function - lua_getglobal(state, PreInitializeFunction); - bool isFunction = lua_isfunction(state, -1); - if (!isFunction) { - LERROR( - "Error executing startup script '" << sceneDescription << "'. Scene '" << - sceneDescription << "' does not have a function '" << - PreInitializeFunction << "'" - ); - return; - } - - // And execute the preinitialize function - int success = lua_pcall(state, 0, 0, 0); - if (success != 0) { - LERROR( - "Error executing '" << PreInitializeFunction << "': " << - lua_tostring(state, -1) - ); - } -} - -void OpenSpaceEngine::runPostInitializationScripts(const std::string& sceneDescription) { - // @CLEANUP: Move this into the scene loading? ---abock - LINFO("Running Setup scripts"); - ghoul::lua::LuaState state; - OsEng.scriptEngine().initializeLuaState(state); - - // First execute the script to get all global variables - ghoul::lua::runScriptFile(state, absPath(sceneDescription)); - - // Get the preinitialize function - lua_getglobal(state, PostInitializationFunction); - bool isFunction = lua_isfunction(state, -1); - if (!isFunction) { - LERROR( - "Error executing startup script '" << sceneDescription << "'. Scene '" << - sceneDescription << "' does not have a function '" << - PostInitializationFunction << "'" - ); - return; - } - - // And execute the preinitialize function - int success = lua_pcall(state, 0, 0, 0); - if (success != 0) { - LERROR( - "Error executing '" << PostInitializationFunction << "': " << - lua_tostring(state, -1) - ); - } -} - -void OpenSpaceEngine::loadFonts() { - ghoul::Dictionary fonts; - configurationManager().getValue(ConfigurationManager::KeyFonts, fonts); - - _fontManager = std::make_unique(FontAtlasSize); - - for (const std::string& key : fonts.keys()) { - std::string font = fonts.value(key); - font = absPath(font); - - if (!FileSys.fileExists(font)) { - LERROR("Could not find font '" << font << "'"); - continue; - } - - LINFO("Registering font '" << font << "' with key '" << key << "'"); - bool success = _fontManager->registerFontPath(key, font); - - if (!success) { - LERROR("Error registering font '" << font << "' with key '" << key << "'"); - } - } - - try { - bool initSuccess = ghoul::fontrendering::FontRenderer::initialize(); - if (!initSuccess) { - LERROR("Error initializing default font renderer"); - } - - ghoul::fontrendering::FontRenderer::defaultRenderer().setFramebufferSize( - _renderEngine->fontResolution() - ); - } - catch (const ghoul::RuntimeError& err) { - LERRORC(err.component, err.message); - } -} - -void OpenSpaceEngine::configureLogging() { - const std::string KeyLogLevel = - ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogLevel; - const std::string KeyLogImmediateFlush = - ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartImmediateFlush; - const std::string KeyLogs = - ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogs; - - if (configurationManager().hasKeyAndValue(KeyLogLevel)) { - std::string logLevel = "Info"; - configurationManager().getValue(KeyLogLevel, logLevel); - - bool immediateFlush = false; - configurationManager().getValue(KeyLogImmediateFlush, immediateFlush); - - LogLevel level = ghoul::logging::levelFromString(logLevel); - LogManager::deinitialize(); - using ImmediateFlush = ghoul::logging::LogManager::ImmediateFlush; - LogManager::initialize( - level, - immediateFlush ? ImmediateFlush::Yes : ImmediateFlush::No - ); - - LogMgr.addLog(std::make_unique()); - } - - if (configurationManager().hasKeyAndValue(KeyLogs)) { - ghoul::Dictionary logs = configurationManager().value(KeyLogs); - - for (size_t i = 1; i <= logs.size(); ++i) { - ghoul::Dictionary logInfo = logs.value(std::to_string(i)); - - try { - LogMgr.addLog(createLog(logInfo)); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - } - -#ifdef WIN32 - if (IsDebuggerPresent()) { - LogMgr.addLog(std::make_unique()); - } -#endif // WIN32 - -#ifndef GHOUL_LOGGING_ENABLE_TRACE - std::string logLevel = "Info"; - configurationManager().getValue(KeyLogLevel, logLevel); - LogLevel level = ghoul::logging::levelFromString(logLevel); - - if (level == ghoul::logging::LogLevel::Trace) { - LWARNING( - "Desired logging level is set to 'Trace' but application was " << - "compiled without Trace support" - ); - } -#endif // GHOUL_LOGGING_ENABLE_TRACE -} - -void OpenSpaceEngine::initializeGL() { - LTRACE("OpenSpaceEngine::initializeGL(begin)"); - - LTRACE("OpenSpaceEngine::initializeGL::Console::initialize(begin)"); - try { - _engine->_console->initialize(); - } - catch (ghoul::RuntimeError& e) { - LERROR("Error initializing Console with error:"); - LERRORC(e.component, e.message); - } - LTRACE("OpenSpaceEngine::initializeGL::Console::initialize(end)"); - - const std::string key = ConfigurationManager::KeyOpenGLDebugContext; - if (_configurationManager->hasKey(key)) { - LTRACE("OpenSpaceEngine::initializeGL::DebugContext(begin)"); - ghoul::Dictionary dict = _configurationManager->value(key); - bool debug = dict.value(ConfigurationManager::PartActivate); - - // Debug output is not available before 4.3 - const ghoul::systemcapabilities::Version minVersion = { 4, 3, 0 }; - if (OpenGLCap.openGLVersion() < minVersion) { - LINFO("OpenGL Debug context requested, but insufficient version available"); - debug = false; - } - - if (debug) { - using namespace ghoul::opengl::debug; - - bool synchronous = true; - if (dict.hasKey(ConfigurationManager::PartSynchronous)) { - synchronous = dict.value(ConfigurationManager::PartSynchronous); - } - - setDebugOutput(DebugOutput(debug), SynchronousOutput(synchronous)); - - - if (dict.hasKey(ConfigurationManager::PartFilterIdentifier)) { - ghoul::Dictionary filterDict = dict.value( - ConfigurationManager::PartFilterIdentifier - ); - - for (size_t i = 1; i <= filterDict.size(); ++i) { - ghoul::Dictionary id = filterDict.value( - std::to_string(i) - ); - - const unsigned int identifier = static_cast( - id.value( - ConfigurationManager::PartFilterIdentifierIdentifier - ) - ); - - const std::string s = id.value( - ConfigurationManager::PartFilterIdentifierSource - ); - - const std::string t = id.value( - ConfigurationManager::PartFilterIdentifierType - ); - - setDebugMessageControl( - ghoul::from_string(s), - ghoul::from_string(t), - { identifier }, - Enabled::No - ); - } - } - - if (dict.hasKey(ConfigurationManager::PartFilterSeverity)) { - ghoul::Dictionary filterDict = dict.value( - ConfigurationManager::PartFilterIdentifier - ); - - for (size_t i = 1; i <= filterDict.size(); ++i) { - std::string severity = filterDict.value( - std::to_string(i) - ); - - setDebugMessageControl( - Source::DontCare, - Type::DontCare, - ghoul::from_string(severity), - Enabled::No - ); - } - } - - auto callback = [](Source source, Type type, Severity severity, - unsigned int id, std::string message) -> void - { - const std::string s = std::to_string(source); - const std::string t = std::to_string(type); - - const std::string category = - "OpenGL (" + s + ") [" + t + "] {" + std::to_string(id) + "}"; - switch (severity) { - case Severity::High: - LERRORC(category, std::string(message)); - break; - case Severity::Medium: - LWARNINGC(category, std::string(message)); - break; - case Severity::Low: - LINFOC(category, std::string(message)); - break; - case Severity::Notification: - LDEBUGC(category, std::string(message)); - break; - default: - throw ghoul::MissingCaseException(); - } - }; - ghoul::opengl::debug::setDebugCallback(callback); - } - LTRACE("OpenSpaceEngine::initializeGL::DebugContext(end)"); - } - - - LINFO("Initializing Rendering Engine"); - _renderEngine->initializeGL(); - - for (const auto& func : _moduleCallbacks.initializeGL) { - func(); - } - - LINFO("Finished initializing OpenGL"); - - LINFO("IsUsingSwapGroups: " << _windowWrapper->isUsingSwapGroups()); - LINFO("IsSwapGroupMaster: " << _windowWrapper->isSwapGroupMaster()); - - LTRACE("OpenSpaceEngine::initializeGL(end)"); -} - -double OpenSpaceEngine::runTime() { - return _runTime; -} - -void OpenSpaceEngine::setRunTime(double d) { - _runTime = d; -} - -void OpenSpaceEngine::preSynchronization() { - LTRACE("OpenSpaceEngine::preSynchronization(begin)"); - FileSys.triggerFilesystemEvents(); - - if (_scheduledSceneSwitch) { - loadScene(_scenePath); - _scheduledSceneSwitch = false; - } - - if (_isFirstRenderingFirstFrame) { - _windowWrapper->setSynchronization(false); - } - - bool master = _windowWrapper->isMaster(); - - _syncEngine->preSynchronization(SyncEngine::IsMaster(master)); - if (master) { - double dt = _windowWrapper->averageDeltaTime(); - _timeManager->preSynchronization(dt); - - using Iter = std::vector::const_iterator; - std::pair scheduledScripts = _scriptScheduler->progressTo( - timeManager().time().j2000Seconds() - ); - for (Iter it = scheduledScripts.first; it != scheduledScripts.second; ++it) { - _scriptEngine->queueScript( - *it, ScriptEngine::RemoteScripting::Yes - ); - } - - _interactionHandler->updateInputStates(dt); - - _renderEngine->updateScene(); - _interactionHandler->updateCamera(dt); - _renderEngine->camera()->invalidateCache(); - - _parallelConnection->preSynchronization(); - } - - for (const auto& func : _moduleCallbacks.preSync) { - func(); - } - LTRACE("OpenSpaceEngine::preSynchronization(end)"); -} - -void OpenSpaceEngine::postSynchronizationPreDraw() { - LTRACE("OpenSpaceEngine::postSynchronizationPreDraw(begin)"); - - bool master = _windowWrapper->isMaster(); - _syncEngine->postSynchronization(SyncEngine::IsMaster(master)); - - if (_shutdown.inShutdown) { - if (_shutdown.timer <= 0.f) { - _windowWrapper->terminate(); - } - _shutdown.timer -= static_cast(_windowWrapper->averageDeltaTime()); - } - - _renderEngine->updateScene(); - _renderEngine->updateFade(); - _renderEngine->updateRenderer(); - _renderEngine->updateScreenSpaceRenderables(); - _renderEngine->updateShaderPrograms(); - - if (!master) { - _renderEngine->camera()->invalidateCache(); - } - - // Step the camera using the current mouse velocities which are synced - //_interactionHandler->updateCamera(); - - for (const auto& func : _moduleCallbacks.postSyncPreDraw) { - func(); - } - - // Testing this every frame has minimal impact on the performance --- abock - // Debug build: 1-2 us ; Release build: <= 1 us - using ghoul::logging::LogManager; - int warningCounter = LogMgr.messageCounter(LogLevel::Warning); - int errorCounter = LogMgr.messageCounter(LogLevel::Error); - int fatalCounter = LogMgr.messageCounter(LogLevel::Fatal); - - if (warningCounter > 0) { - LWARNINGC("Logging", "Number of Warnings raised: " << warningCounter); - } - if (errorCounter > 0) { - LWARNINGC("Logging", "Number of Errors raised: " << errorCounter); - } - if (fatalCounter > 0) { - LWARNINGC("Logging", "Number of Fatals raised: " << fatalCounter); - } - - LogMgr.resetMessageCounters(); - - LTRACE("OpenSpaceEngine::postSynchronizationPreDraw(end)"); -} - -void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, - const glm::mat4& viewMatrix, - const glm::mat4& projectionMatrix) -{ - bool isGuiWindow = _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; - bool showOverlay = isGuiWindow && _windowWrapper->isMaster() && _windowWrapper->isRegularRendering(); - // @CLEANUP: Replace the two windows by a single call to whether a gui should be - // rendered ---abock - - if (showOverlay) { - _console->update(); - } - - LTRACE("OpenSpaceEngine::render(begin)"); - _renderEngine->render(sceneMatrix, viewMatrix, projectionMatrix); - - for (const auto& func : _moduleCallbacks.render) { - func(); - } - - if (showOverlay) { - _renderEngine->renderScreenLog(); - _console->render(); - } - - if (_shutdown.inShutdown) { - _renderEngine->renderShutdownInformation(_shutdown.timer, _shutdown.waitTime); - } - - LTRACE("OpenSpaceEngine::render(end)"); -} - -void OpenSpaceEngine::postDraw() { - LTRACE("OpenSpaceEngine::postDraw(begin)"); - - _renderEngine->postDraw(); - - for (const auto& func : _moduleCallbacks.postDraw) { - func(); - } - - if (_isFirstRenderingFirstFrame) { - _windowWrapper->setSynchronization(true); - _isFirstRenderingFirstFrame = false; - } - - LTRACE("OpenSpaceEngine::postDraw(end)"); -} - -void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction action) { - for (const auto& func : _moduleCallbacks.keyboard) { - const bool consumed = func(key, mod, action); - if (consumed) { - return; - } - } - - const bool consoleConsumed = _console->keyboardCallback(key, mod, action); - if (consoleConsumed) { - return; - } - - _interactionHandler->keyboardCallback(key, mod, action); -} - -void OpenSpaceEngine::charCallback(unsigned int codepoint, KeyModifier modifier) { - for (const auto& func : _moduleCallbacks.character) { - bool consumed = func(codepoint, modifier); - if (consumed) { - return; - } - } - - _console->charCallback(codepoint, modifier); -} - -void OpenSpaceEngine::mouseButtonCallback(MouseButton button, MouseAction action) { - for (const auto& func : _moduleCallbacks.mouseButton) { - bool consumed = func(button, action); - if (consumed) { - return; - } - } - - _interactionHandler->mouseButtonCallback(button, action); -} - -void OpenSpaceEngine::mousePositionCallback(double x, double y) { - for (const auto& func : _moduleCallbacks.mousePosition) { - func(x, y); - } - - _interactionHandler->mousePositionCallback(x, y); -} - -void OpenSpaceEngine::mouseScrollWheelCallback(double pos) { - for (const auto& func : _moduleCallbacks.mouseScrollWheel) { - bool consumed = func(pos); - if (consumed) { - return; - } - } - - _interactionHandler->mouseScrollWheelCallback(pos); -} - -void OpenSpaceEngine::encode() { - _syncEngine->encodeSyncables(); - - _networkEngine->publishStatusMessage(); - _networkEngine->sendMessages(); -} - -void OpenSpaceEngine::decode() { - _syncEngine->decodeSyncables(); -} - -void OpenSpaceEngine::externalControlCallback(const char* receivedChars, int size, - int clientId) -{ - if (size == 0) { - return; - } - - _networkEngine->handleMessage(std::string(receivedChars, size)); -} - -void OpenSpaceEngine::toggleShutdownMode() { - if (_shutdown.inShutdown) { - // If we are already in shutdown mode, we want to disable it - LINFO("Disabled shutdown mode"); - _shutdown.inShutdown = false; - } - else { - // Else, we have to enable it - LINFO("Shutting down OpenSpace"); - _shutdown.timer = _shutdown.waitTime; - _shutdown.inShutdown = true; - } -} - -scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { - return { - "", - { - { - "toggleShutdown", - &luascriptfunctions::toggleShutdown, - "", - "Toggles the shutdown mode that will close the application after the count" - "down timer is reached" - }, - { - "writeDocumentation", - &luascriptfunctions::writeDocumentation, - "", - "Writes out documentation files" - }, - { - "downloadFile", - &luascriptfunctions::downloadFile, - "", - "Downloads a file from Lua scope" - }, - { - "addVirtualProperty", - &luascriptfunctions::addVirtualProperty, - "type, name, identifier, [value, minimumValue, maximumValue]", - "Adds a virtual property that will set a group of properties" - }, - { - "removeVirtualProperty", - &luascriptfunctions::removeVirtualProperty, - "string", - "Removes a previously added virtual property" - }, - { - "removeAllVirtualProperties", - &luascriptfunctions::removeAllVirtualProperties, - "", - "Remove all registered virtual properties" - } - } - }; -} - -void OpenSpaceEngine::enableBarrier() { - _windowWrapper->setBarrier(true); -} - -void OpenSpaceEngine::disableBarrier() { - _windowWrapper->setBarrier(false); -} - -// Registers a callback for a specific CallbackOption -void OpenSpaceEngine::registerModuleCallback(OpenSpaceEngine::CallbackOption option, - std::function function) -{ - switch (option) { - case CallbackOption::Initialize: - _moduleCallbacks.initialize.push_back(std::move(function)); - break; - case CallbackOption::Deinitialize: - _moduleCallbacks.deinitialize.push_back(std::move(function)); - break; - case CallbackOption::InitializeGL: - _moduleCallbacks.initializeGL.push_back(std::move(function)); - break; - case CallbackOption::DeinitializeGL: - _moduleCallbacks.deinitializeGL.push_back(std::move(function)); - break; - case CallbackOption::PreSync: - _moduleCallbacks.preSync.push_back(std::move(function)); - break; - case CallbackOption::PostSyncPreDraw: - _moduleCallbacks.postSyncPreDraw.push_back(std::move(function)); - break; - case CallbackOption::Render: - _moduleCallbacks.render.push_back(std::move(function)); - break; - case CallbackOption::PostDraw: - _moduleCallbacks.postDraw.push_back(std::move(function)); - break; - default: - throw ghoul::MissingCaseException(); - } -} - -void OpenSpaceEngine::registerModuleKeyboardCallback( - std::function function) -{ - _moduleCallbacks.keyboard.push_back(std::move(function)); -} - -void OpenSpaceEngine::registerModuleCharCallback( - std::function function) -{ - _moduleCallbacks.character.push_back(std::move(function)); -} - -void OpenSpaceEngine::registerModuleMouseButtonCallback( - std::function function) -{ - _moduleCallbacks.mouseButton.push_back(std::move(function)); -} - -void OpenSpaceEngine::registerModuleMousePositionCallback( - std::function function) -{ - _moduleCallbacks.mousePosition.push_back(std::move(function)); -} - -void OpenSpaceEngine::registerModuleMouseScrollWheelCallback( - std::function function) -{ - _moduleCallbacks.mouseScrollWheel.push_back(std::move(function)); -} - -ConfigurationManager& OpenSpaceEngine::configurationManager() { - ghoul_assert(_configurationManager, "ConfigurationManager must not be nullptr"); - return *_configurationManager; -} - -LuaConsole& OpenSpaceEngine::console() { - ghoul_assert(_console, "LuaConsole must not be nullptr"); - return *_console; -} - -DownloadManager& OpenSpaceEngine::downloadManager() { - ghoul_assert(_downloadManager, "Download Manager must not be nullptr"); - return *_downloadManager; -} - -NetworkEngine& OpenSpaceEngine::networkEngine() { - ghoul_assert(_networkEngine, "NetworkEngine must not be nullptr"); - return *_networkEngine; -} - -ModuleEngine& OpenSpaceEngine::moduleEngine() { - ghoul_assert(_moduleEngine, "ModuleEngine must not be nullptr"); - return *_moduleEngine; -} - -ParallelConnection& OpenSpaceEngine::parallelConnection() { - ghoul_assert(_parallelConnection, "ParallelConnection must not be nullptr"); - return *_parallelConnection; -} - -RenderEngine& OpenSpaceEngine::renderEngine() { - ghoul_assert(_renderEngine, "RenderEngine must not be nullptr"); - return *_renderEngine; -} - -SettingsEngine& OpenSpaceEngine::settingsEngine() { - ghoul_assert(_settingsEngine, "Settings Engine must not be nullptr"); - return *_settingsEngine; -} - -TimeManager& OpenSpaceEngine::timeManager() { - ghoul_assert(_timeManager, "Download Manager must not be nullptr"); - return *_timeManager; -} - -WindowWrapper& OpenSpaceEngine::windowWrapper() { - ghoul_assert(_windowWrapper, "Window Wrapper must not be nullptr"); - return *_windowWrapper; -} - -ghoul::fontrendering::FontManager& OpenSpaceEngine::fontManager() { - ghoul_assert(_fontManager, "Font Manager must not be nullptr"); - return *_fontManager; -} - -interaction::InteractionHandler& OpenSpaceEngine::interactionHandler() { - ghoul_assert(_interactionHandler, "InteractionHandler must not be nullptr"); - return *_interactionHandler; -} - -properties::PropertyOwner& OpenSpaceEngine::globalPropertyOwner() { - ghoul_assert( - _globalPropertyNamespace, - "Global Property Namespace must not be nullptr" - ); - return *_globalPropertyNamespace; -} - -VirtualPropertyManager& OpenSpaceEngine::virtualPropertyManager() { - ghoul_assert( - _virtualPropertyManager, - "Virtual Property Manager must not be nullptr" - ); - - return *_virtualPropertyManager; -} - -ScriptEngine& OpenSpaceEngine::scriptEngine() { - ghoul_assert(_scriptEngine, "ScriptEngine must not be nullptr"); - return *_scriptEngine; -} - -ScriptScheduler& OpenSpaceEngine::scriptScheduler() { - ghoul_assert(_scriptScheduler, "ScriptScheduler must not be nullptr"); - return *_scriptScheduler; -} - -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined(_MSC_VER) && defined(OPENSPACE_ENABLE_VLD) +#include +#endif + +#ifdef WIN32 +#include +#endif + +#include "openspaceengine_lua.inl" + +using namespace openspace::scripting; +using namespace ghoul::filesystem; +using namespace ghoul::logging; +using namespace ghoul::cmdparser; + +namespace { + const char* _loggerCat = "OpenSpaceEngine"; + const char* SgctDefaultConfigFile = "${SGCT}/single.xml"; + + const char* SgctConfigArgumentCommand = "-config"; + + const char* PreInitializeFunction = "preInitialization"; + const char* PostInitializationFunction = "postInitialization"; + + const int CacheVersion = 1; + const int DownloadVersion = 1; + + const glm::ivec3 FontAtlasSize{ 1536, 1536, 1 }; + + + struct { + std::string configurationName; + std::string sgctConfigurationName; + std::string sceneName; + std::string cacheFolder; + } commandlineArgumentPlaceholders; +} + +namespace openspace { + +namespace properties { + class Property; +} + +class Scene; + +OpenSpaceEngine* OpenSpaceEngine::_engine = nullptr; + +OpenSpaceEngine::OpenSpaceEngine(std::string programName, + std::unique_ptr windowWrapper) + : _configurationManager(new ConfigurationManager) + , _sceneManager(new SceneManager) + , _downloadManager(nullptr) + , _console(new LuaConsole) + , _moduleEngine(new ModuleEngine) + , _networkEngine(new NetworkEngine) + , _parallelConnection(new ParallelConnection) + , _renderEngine(new RenderEngine) + , _settingsEngine(new SettingsEngine) + , _syncEngine(std::make_unique(4096)) + , _timeManager(new TimeManager) + , _windowWrapper(std::move(windowWrapper)) + , _commandlineParser(new ghoul::cmdparser::CommandlineParser( + programName, ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes + )) + , _interactionHandler(new interaction::InteractionHandler) + , _scriptEngine(new scripting::ScriptEngine) + , _scriptScheduler(new scripting::ScriptScheduler) + , _virtualPropertyManager(new VirtualPropertyManager) + , _globalPropertyNamespace(new properties::PropertyOwner("")) + , _scheduledSceneSwitch(false) + , _scenePath("") + , _runTime(0.0) + , _shutdown({false, 0.f, 0.f}) + , _isFirstRenderingFirstFrame(true) +{ + _interactionHandler->setPropertyOwner(_globalPropertyNamespace.get()); + + // New property subowners also have to be added to the OnScreenGuiModule callback! + _globalPropertyNamespace->addPropertySubOwner(_interactionHandler.get()); + _globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get()); + _globalPropertyNamespace->addPropertySubOwner(_renderEngine.get()); + _globalPropertyNamespace->addPropertySubOwner(_windowWrapper.get()); + _globalPropertyNamespace->addPropertySubOwner(_parallelConnection.get()); + _globalPropertyNamespace->addPropertySubOwner(_console.get()); + + FactoryManager::initialize(); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Renderable" + ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Translation" + ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Rotation" + ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Scale" + ); + FactoryManager::ref().addFactory( + std::make_unique>(), + "Task" + ); + + SpiceManager::initialize(); + TransformationManager::initialize(); +} + +OpenSpaceEngine& OpenSpaceEngine::ref() { + ghoul_assert(_engine, "OpenSpaceEngine not created"); + return *_engine; +} + +bool OpenSpaceEngine::isCreated() { + return _engine != nullptr; +} + +void OpenSpaceEngine::create(int argc, char** argv, + std::unique_ptr windowWrapper, + std::vector& sgctArguments, bool& requestClose) +{ + ghoul_assert(!_engine, "OpenSpaceEngine was already created"); + ghoul_assert(windowWrapper != nullptr, "No Window Wrapper was provided"); + + requestClose = false; + + ghoul::initialize(); + + // Initialize the LogManager and add the console log as this will be used every time + // and we need a fall back if something goes wrong between here and when we add the + // logs from the configuration file. If the user requested as specific loglevel in the + // configuration file, we will deinitialize this LogManager and reinitialize it later + // with the correct LogLevel + LogManager::initialize( + LogLevel::Debug, + ghoul::logging::LogManager::ImmediateFlush::Yes + ); + LogMgr.addLog(std::make_unique()); + + LDEBUG("Initialize FileSystem"); + +#ifdef __APPLE__ + ghoul::filesystem::File app(argv[0]); + std::string dirName = app.directoryName(); + LINFO("Setting starting directory to '" << dirName << "'"); + FileSys.setCurrentDirectory(dirName); +#endif + + // Sanity check of values + if (argc < 1 || argv == nullptr) { + throw ghoul::RuntimeError( + "No arguments were passed to this function", + "OpenSpaceEngine" + ); + } + + // Create other objects + LDEBUG("Creating OpenSpaceEngine"); + _engine = new OpenSpaceEngine(std::string(argv[0]), std::move(windowWrapper)); + + // Query modules for commandline arguments + _engine->gatherCommandlineArguments(); + + // Parse commandline arguments + std::vector args(argv, argv + argc); + std::shared_ptr> arguments = + _engine->_commandlineParser->setCommandLine(args); + + bool showHelp = _engine->_commandlineParser->execute(); + if (showHelp) { + _engine->_commandlineParser->displayHelp(); + requestClose = true; + return; + } + sgctArguments = *arguments; + + // Find configuration + std::string configurationFilePath = commandlineArgumentPlaceholders.configurationName; + if (configurationFilePath.empty()) { + LDEBUG("Finding configuration"); + configurationFilePath = + ConfigurationManager::findConfiguration(configurationFilePath); + } + configurationFilePath = absPath(configurationFilePath); + + if (!FileSys.fileExists(configurationFilePath)) { + throw ghoul::FileNotFoundError( + "Configuration file '" + configurationFilePath + "' not found" + ); + } + LINFO("Configuration Path: '" << configurationFilePath << "'"); + + // Loading configuration from disk + LDEBUG("Loading configuration from disk"); + try { + _engine->configurationManager().loadFromFile(configurationFilePath); + } + catch (const documentation::SpecificationError& e) { + LFATAL("Loading of configuration file '" << configurationFilePath << "' failed"); + for (const documentation::TestResult::Offense& o : e.result.offenses) { + LERRORC(o.offender, std::to_string(o.reason)); + } + for (const documentation::TestResult::Warning& w : e.result.warnings) { + LWARNINGC(w.offender, std::to_string(w.reason)); + } + throw; + } + catch (const ghoul::RuntimeError&) { + LFATAL("Loading of configuration file '" << configurationFilePath << "' failed"); + throw; + } + + const bool hasCacheCommandline = !commandlineArgumentPlaceholders.cacheFolder.empty(); + const bool hasCacheConfiguration = _engine->configurationManager().hasKeyAndValue( + ConfigurationManager::KeyPerSceneCache + ); + std::string cacheFolder = absPath("${CACHE}"); + if (hasCacheCommandline) { + cacheFolder = commandlineArgumentPlaceholders.cacheFolder; + // @CLEANUP: Why is this commented out? ---abock + //FileSys.registerPathToken( + // "${CACHE}", + // commandlineArgumentPlaceholders.cacheFolder, + // ghoul::filesystem::FileSystem::Override::Yes + //); + } + if (hasCacheConfiguration) { + std::string scene = _engine->configurationManager().value( + ConfigurationManager::KeyConfigScene + ); + cacheFolder += "-" + ghoul::filesystem::File(scene).baseName(); + } + + if (hasCacheCommandline || hasCacheConfiguration) { + LINFO("Old cache: " << absPath("${CACHE}")); + LINFO("New cache: " << cacheFolder); + FileSys.registerPathToken( + "${CACHE}", + cacheFolder, + ghoul::filesystem::FileSystem::Override::Yes + ); + } + + // Initialize the requested logs from the configuration file + _engine->configureLogging(); + + LINFOC("OpenSpace Version", + OPENSPACE_VERSION_MAJOR << "." << + OPENSPACE_VERSION_MINOR << "." << + OPENSPACE_VERSION_PATCH << + " (" << OPENSPACE_VERSION_STRING << ")" + ); + + // Create directories that doesn't exist + auto tokens = FileSys.tokens(); + for (const std::string& token : tokens) { + if (!FileSys.directoryExists(token)) { + std::string p = absPath(token); + LDEBUG("Directory '" << p << "' does not exist, creating."); + FileSys.createDirectory(p, ghoul::filesystem::FileSystem::Recursive::Yes); + } + } + + // Register modules + _engine->_moduleEngine->initialize(); + + // After registering the modules, the documentations for the available classes + // can be added as well + for (OpenSpaceModule* m : _engine->_moduleEngine->modules()) { + for (const documentation::Documentation& doc : m->documentations()) { + DocEng.addDocumentation(doc); + } + } + + // Create the cachemanager + FileSys.createCacheManager( + absPath("${" + ConfigurationManager::KeyCache + "}"), CacheVersion + ); + + // Register the provided shader directories + ghoul::opengl::ShaderPreprocessor::addIncludePath(absPath("${SHADERS}")); + + // Determining SGCT configuration file + LDEBUG("Determining SGCT configuration file"); + std::string sgctConfigurationPath = SgctDefaultConfigFile; + _engine->configurationManager().getValue( + ConfigurationManager::KeyConfigSgct, sgctConfigurationPath); + + if (!commandlineArgumentPlaceholders.sgctConfigurationName.empty()) { + LDEBUG("Overwriting SGCT configuration file with commandline argument: " << + commandlineArgumentPlaceholders.sgctConfigurationName); + sgctConfigurationPath = commandlineArgumentPlaceholders.sgctConfigurationName; + } + + // Prepend the outgoing sgctArguments with the program name + // as well as the configuration file that sgct is supposed to use + sgctArguments.insert(sgctArguments.begin(), argv[0]); + sgctArguments.insert(sgctArguments.begin() + 1, SgctConfigArgumentCommand); + sgctArguments.insert(sgctArguments.begin() + 2, absPath(sgctConfigurationPath)); +} + +void OpenSpaceEngine::destroy() { + if (_engine->parallelConnection().status() != ParallelConnection::Status::Disconnected) { + _engine->parallelConnection().signalDisconnect(); + } + + LTRACE("OpenSpaceEngine::destroy(begin)"); + for (const auto& func : _engine->_moduleCallbacks.deinitializeGL) { + func(); + } + + for (const auto& func : _engine->_moduleCallbacks.deinitialize) { + func(); + } + + _engine->_syncEngine->removeSyncables(_engine->timeManager().getSyncables()); + _engine->_syncEngine->removeSyncables(_engine->_renderEngine->getSyncables()); + _engine->_syncEngine->removeSyncable(_engine->_scriptEngine.get()); + + _engine->_moduleEngine->deinitialize(); + _engine->_console->deinitialize(); + + _engine->_scriptEngine->deinitialize(); + _engine->_sceneManager->unloadAll(); + + delete _engine; + FactoryManager::deinitialize(); + SpiceManager::deinitialize(); + + ghoul::fontrendering::FontRenderer::deinitialize(); + + LogManager::deinitialize(); + + ghoul::deinitialize(); + LTRACE("OpenSpaceEngine::destroy(end)"); +} + +void OpenSpaceEngine::initialize() { + LTRACE("OpenSpaceEngine::initialize(begin)"); + + glbinding::Binding::useCurrentContext(); + glbinding::Binding::initialize(); + + // clear the screen so the user don't have to see old buffer contents from the + // graphics card + LDEBUG("Clearing all Windows"); + _windowWrapper->clearAllWindows(glm::vec4(0.f, 0.f, 0.f, 1.f)); + + LDEBUG("Adding system components"); + // Detect and log OpenCL and OpenGL versions and available devices + SysCap.addComponent( + std::make_unique() + ); + SysCap.addComponent( + std::make_unique() + ); + + // @BUG: This will call OpenGL functions, should it should be in the initializeGL + LDEBUG("Detecting capabilities"); + SysCap.detectCapabilities(); + + using Verbosity = ghoul::systemcapabilities::SystemCapabilitiesComponent::Verbosity; + Verbosity verbosity = Verbosity::Default; + if (configurationManager().hasKey(ConfigurationManager::KeyCapabilitiesVerbosity)) { + static const std::map VerbosityMap = { + { "None", Verbosity::None }, + { "Minimal", Verbosity::Minimal }, + { "Default", Verbosity::Default }, + { "Full", Verbosity::Full } + }; + + std::string v = configurationManager().value( + ConfigurationManager::KeyCapabilitiesVerbosity + ); + ghoul_assert( + VerbosityMap.find(v) != VerbosityMap.end(), + "Missing check for syscaps verbosity in openspace.cfg documentation" + ); + verbosity = VerbosityMap.find(v)->second; + } + SysCap.logCapabilities(verbosity); + + // Check the required OpenGL versions of the registered modules + ghoul::systemcapabilities::Version version = + _engine->_moduleEngine->requiredOpenGLVersion(); + LINFO("Required OpenGL version: " << std::to_string(version)); + + if (OpenGLCap.openGLVersion() < version) { + throw ghoul::RuntimeError( + "Module required higher OpenGL version than is supported", + "OpenSpaceEngine" + ); + } + + if (configurationManager().hasKey(ConfigurationManager::KeyDownloadRequestURL)) { + const std::string requestUrl = configurationManager().value( + ConfigurationManager::KeyDownloadRequestURL + ); + + _downloadManager = std::make_unique( + requestUrl, + DownloadVersion + ); + } + + // Register Lua script functions + LDEBUG("Registering Lua libraries"); + registerCoreClasses(*_scriptEngine); + + for (OpenSpaceModule* module : _moduleEngine->modules()) { + _scriptEngine->addLibrary(module->luaLibrary()); + } + + // TODO: Maybe move all scenegraph and renderengine stuff to initializeGL + scriptEngine().initialize(); + + writeDocumentation(); + + if (configurationManager().hasKey(ConfigurationManager::KeyShutdownCountdown)) { + _shutdown.waitTime = static_cast(configurationManager().value( + ConfigurationManager::KeyShutdownCountdown + )); + } + + if (!commandlineArgumentPlaceholders.sceneName.empty()) { + configurationManager().setValue( + ConfigurationManager::KeyConfigScene, + commandlineArgumentPlaceholders.sceneName + ); + } + + // Initialize the SettingsEngine + _settingsEngine->initialize(); + _settingsEngine->setModules(_moduleEngine->modules()); + + // Initialize the InteractionHandler + _interactionHandler->initialize(); + + // Load a light and a monospaced font + loadFonts(); + + std::string scenePath = ""; + configurationManager().getValue(ConfigurationManager::KeyConfigScene, scenePath); + + _renderEngine->initialize(); + + for (const auto& func : _moduleCallbacks.initialize) { + func(); + } + + scheduleLoadScene(scenePath); + + LTRACE("OpenSpaceEngine::initialize(end)"); + +} + +void OpenSpaceEngine::scheduleLoadScene(std::string scenePath) { + _scheduledSceneSwitch = true; + _scenePath = std::move(scenePath); +} + +void OpenSpaceEngine::loadScene(const std::string& scenePath) { + LTRACE("OpenSpaceEngine::loadScene(begin)"); + + windowWrapper().setBarrier(false); + windowWrapper().setSynchronization(false); + OnExit( + [this]() { + windowWrapper().setSynchronization(true); + windowWrapper().setBarrier(true); + } + ); + + // Run start up scripts + try { + runPreInitializationScripts(scenePath); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + + Scene* scene; + try { + scene = _sceneManager->loadScene(scenePath); + } catch (const ghoul::FileNotFoundError& e) { + LERRORC(e.component, e.message); + return; + } catch (const Scene::InvalidSceneError& e) { + LERRORC(e.component, e.message); + return; + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + return; + } + catch (const std::exception& e) { + LERROR(e.what()); + return; + } + catch (...) { + LERROR("Unknown error loading the scene"); + return; + } + + Scene* previousScene = _renderEngine->scene(); + if (previousScene) { + _syncEngine->removeSyncables(_timeManager->getSyncables()); + _syncEngine->removeSyncables(_renderEngine->getSyncables()); + _syncEngine->removeSyncable(_scriptEngine.get()); + + _renderEngine->setScene(nullptr); + _renderEngine->setCamera(nullptr); + _sceneManager->unloadScene(*previousScene); + } + + // Initialize the RenderEngine + _renderEngine->setScene(scene); + _renderEngine->setCamera(scene->camera()); + _renderEngine->setGlobalBlackOutFactor(0.0); + _renderEngine->startFading(1, 3.0); + + scene->initialize(); + _interactionHandler->setCamera(scene->camera()); + + try { + runPostInitializationScripts(scenePath); + } + catch (const ghoul::RuntimeError& e) { + LFATALC(e.component, e.message); + } + + // Write keyboard documentation. + if (configurationManager().hasKey(ConfigurationManager::KeyKeyboardShortcuts)) { + interactionHandler().writeDocumentation( + absPath(configurationManager().value( + ConfigurationManager::KeyKeyboardShortcuts + )) + ); + } + + // If a PropertyDocumentationFile was specified, generate it now. + if (configurationManager().hasKey(ConfigurationManager::KeyPropertyDocumentation)) { + scene->writeDocumentation( + absPath(configurationManager().value( + ConfigurationManager::KeyPropertyDocumentation + )) + ); + } + + _syncEngine->addSyncables(_timeManager->getSyncables()); + _syncEngine->addSyncables(_renderEngine->getSyncables()); + _syncEngine->addSyncable(_scriptEngine.get()); + + LTRACE("OpenSpaceEngine::loadScene(end)"); +} + +void OpenSpaceEngine::deinitialize() { + LTRACE("OpenSpaceEngine::deinitialize(begin)"); + + _interactionHandler->deinitialize(); + _renderEngine->deinitialize(); + + LTRACE("OpenSpaceEngine::deinitialize(end)"); +} + +void OpenSpaceEngine::writeDocumentation() { + // If a LuaDocumentationFile was specified, generate it now + if (configurationManager().hasKey(ConfigurationManager::KeyLuaDocumentation)) { + _scriptEngine->writeDocumentation( + absPath(configurationManager().value( + ConfigurationManager::KeyLuaDocumentation + )) + ); + } + + // If a general documentation was specified, generate it now + if (configurationManager().hasKey(ConfigurationManager::KeyDocumentation)) { + DocEng.writeDocumentation( + absPath(configurationManager().value( + ConfigurationManager::KeyDocumentation + )) + ); + } + + // If a factory documentation was specified, generate it now + if (configurationManager().hasKey(ConfigurationManager::KeyFactoryDocumentation)) { + FactoryManager::ref().writeDocumentation( + absPath(configurationManager().value( + ConfigurationManager::KeyFactoryDocumentation + )) + ); + } +} + +void OpenSpaceEngine::gatherCommandlineArguments() { + commandlineArgumentPlaceholders.configurationName = ""; + _commandlineParser->addCommand(std::make_unique>( + &commandlineArgumentPlaceholders.configurationName, "-config", "-c", + "Provides the path to the OpenSpace configuration file" + )); + + commandlineArgumentPlaceholders.sgctConfigurationName = ""; + _commandlineParser->addCommand(std::make_unique>( + &commandlineArgumentPlaceholders.sgctConfigurationName, "-sgct", "-s", + "Provides the path to the SGCT configuration file, overriding the value set in " + "the OpenSpace configuration file" + )); + + commandlineArgumentPlaceholders.sceneName = ""; + _commandlineParser->addCommand(std::make_unique>( + &commandlineArgumentPlaceholders.sceneName, "-scene", "", "Provides the path to " + "the scene file, overriding the value set in the OpenSpace configuration file" + )); + + commandlineArgumentPlaceholders.cacheFolder = ""; + _commandlineParser->addCommand(std::make_unique>( + &commandlineArgumentPlaceholders.cacheFolder, "-cacheDir", "", "Provides the " + "path to a cache file, overriding the value set in the OpenSpace configuration " + "file" + )); +} + +void OpenSpaceEngine::runPreInitializationScripts(const std::string& sceneDescription) { + // @CLEANUP: Move this into the scene loading? ---abock + LINFO("Running Initialization scripts"); + + ghoul::lua::LuaState state; + OsEng.scriptEngine().initializeLuaState(state); + + // First execute the script to get all global variables + ghoul::lua::runScriptFile(state, absPath(sceneDescription)); + + // Get the preinitialize function + lua_getglobal(state, PreInitializeFunction); + bool isFunction = lua_isfunction(state, -1); + if (!isFunction) { + LERROR( + "Error executing startup script '" << sceneDescription << "'. Scene '" << + sceneDescription << "' does not have a function '" << + PreInitializeFunction << "'" + ); + return; + } + + // And execute the preinitialize function + int success = lua_pcall(state, 0, 0, 0); + if (success != 0) { + LERROR( + "Error executing '" << PreInitializeFunction << "': " << + lua_tostring(state, -1) + ); + } +} + +void OpenSpaceEngine::runPostInitializationScripts(const std::string& sceneDescription) { + // @CLEANUP: Move this into the scene loading? ---abock + LINFO("Running Setup scripts"); + ghoul::lua::LuaState state; + OsEng.scriptEngine().initializeLuaState(state); + + // First execute the script to get all global variables + ghoul::lua::runScriptFile(state, absPath(sceneDescription)); + + // Get the preinitialize function + lua_getglobal(state, PostInitializationFunction); + bool isFunction = lua_isfunction(state, -1); + if (!isFunction) { + LERROR( + "Error executing startup script '" << sceneDescription << "'. Scene '" << + sceneDescription << "' does not have a function '" << + PostInitializationFunction << "'" + ); + return; + } + + // And execute the preinitialize function + int success = lua_pcall(state, 0, 0, 0); + if (success != 0) { + LERROR( + "Error executing '" << PostInitializationFunction << "': " << + lua_tostring(state, -1) + ); + } +} + +void OpenSpaceEngine::loadFonts() { + ghoul::Dictionary fonts; + configurationManager().getValue(ConfigurationManager::KeyFonts, fonts); + + _fontManager = std::make_unique(FontAtlasSize); + + for (const std::string& key : fonts.keys()) { + std::string font = fonts.value(key); + font = absPath(font); + + if (!FileSys.fileExists(font)) { + LERROR("Could not find font '" << font << "'"); + continue; + } + + LINFO("Registering font '" << font << "' with key '" << key << "'"); + bool success = _fontManager->registerFontPath(key, font); + + if (!success) { + LERROR("Error registering font '" << font << "' with key '" << key << "'"); + } + } + + try { + bool initSuccess = ghoul::fontrendering::FontRenderer::initialize(); + if (!initSuccess) { + LERROR("Error initializing default font renderer"); + } + + ghoul::fontrendering::FontRenderer::defaultRenderer().setFramebufferSize( + _renderEngine->fontResolution() + ); + } + catch (const ghoul::RuntimeError& err) { + LERRORC(err.component, err.message); + } +} + +void OpenSpaceEngine::configureLogging() { + const std::string KeyLogLevel = + ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogLevel; + const std::string KeyLogImmediateFlush = + ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartImmediateFlush; + const std::string KeyLogs = + ConfigurationManager::KeyLogging + '.' + ConfigurationManager::PartLogs; + + if (configurationManager().hasKeyAndValue(KeyLogLevel)) { + std::string logLevel = "Info"; + configurationManager().getValue(KeyLogLevel, logLevel); + + bool immediateFlush = false; + configurationManager().getValue(KeyLogImmediateFlush, immediateFlush); + + LogLevel level = ghoul::logging::levelFromString(logLevel); + LogManager::deinitialize(); + using ImmediateFlush = ghoul::logging::LogManager::ImmediateFlush; + LogManager::initialize( + level, + immediateFlush ? ImmediateFlush::Yes : ImmediateFlush::No + ); + + LogMgr.addLog(std::make_unique()); + } + + if (configurationManager().hasKeyAndValue(KeyLogs)) { + ghoul::Dictionary logs = configurationManager().value(KeyLogs); + + for (size_t i = 1; i <= logs.size(); ++i) { + ghoul::Dictionary logInfo = logs.value(std::to_string(i)); + + try { + LogMgr.addLog(createLog(logInfo)); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + } + +#ifdef WIN32 + if (IsDebuggerPresent()) { + LogMgr.addLog(std::make_unique()); + } +#endif // WIN32 + +#ifndef GHOUL_LOGGING_ENABLE_TRACE + std::string logLevel = "Info"; + configurationManager().getValue(KeyLogLevel, logLevel); + LogLevel level = ghoul::logging::levelFromString(logLevel); + + if (level == ghoul::logging::LogLevel::Trace) { + LWARNING( + "Desired logging level is set to 'Trace' but application was " << + "compiled without Trace support" + ); + } +#endif // GHOUL_LOGGING_ENABLE_TRACE +} + +void OpenSpaceEngine::initializeGL() { + LTRACE("OpenSpaceEngine::initializeGL(begin)"); + + LTRACE("OpenSpaceEngine::initializeGL::Console::initialize(begin)"); + try { + _engine->_console->initialize(); + } + catch (ghoul::RuntimeError& e) { + LERROR("Error initializing Console with error:"); + LERRORC(e.component, e.message); + } + LTRACE("OpenSpaceEngine::initializeGL::Console::initialize(end)"); + + const std::string key = ConfigurationManager::KeyOpenGLDebugContext; + if (_configurationManager->hasKey(key)) { + LTRACE("OpenSpaceEngine::initializeGL::DebugContext(begin)"); + ghoul::Dictionary dict = _configurationManager->value(key); + bool debug = dict.value(ConfigurationManager::PartActivate); + + // Debug output is not available before 4.3 + const ghoul::systemcapabilities::Version minVersion = { 4, 3, 0 }; + if (OpenGLCap.openGLVersion() < minVersion) { + LINFO("OpenGL Debug context requested, but insufficient version available"); + debug = false; + } + + if (debug) { + using namespace ghoul::opengl::debug; + + bool synchronous = true; + if (dict.hasKey(ConfigurationManager::PartSynchronous)) { + synchronous = dict.value(ConfigurationManager::PartSynchronous); + } + + setDebugOutput(DebugOutput(debug), SynchronousOutput(synchronous)); + + + if (dict.hasKey(ConfigurationManager::PartFilterIdentifier)) { + ghoul::Dictionary filterDict = dict.value( + ConfigurationManager::PartFilterIdentifier + ); + + for (size_t i = 1; i <= filterDict.size(); ++i) { + ghoul::Dictionary id = filterDict.value( + std::to_string(i) + ); + + const unsigned int identifier = static_cast( + id.value( + ConfigurationManager::PartFilterIdentifierIdentifier + ) + ); + + const std::string s = id.value( + ConfigurationManager::PartFilterIdentifierSource + ); + + const std::string t = id.value( + ConfigurationManager::PartFilterIdentifierType + ); + + setDebugMessageControl( + ghoul::from_string(s), + ghoul::from_string(t), + { identifier }, + Enabled::No + ); + } + } + + if (dict.hasKey(ConfigurationManager::PartFilterSeverity)) { + ghoul::Dictionary filterDict = dict.value( + ConfigurationManager::PartFilterIdentifier + ); + + for (size_t i = 1; i <= filterDict.size(); ++i) { + std::string severity = filterDict.value( + std::to_string(i) + ); + + setDebugMessageControl( + Source::DontCare, + Type::DontCare, + ghoul::from_string(severity), + Enabled::No + ); + } + } + + auto callback = [](Source source, Type type, Severity severity, + unsigned int id, std::string message) -> void + { + const std::string s = std::to_string(source); + const std::string t = std::to_string(type); + + const std::string category = + "OpenGL (" + s + ") [" + t + "] {" + std::to_string(id) + "}"; + switch (severity) { + case Severity::High: + LERRORC(category, std::string(message)); + break; + case Severity::Medium: + LWARNINGC(category, std::string(message)); + break; + case Severity::Low: + LINFOC(category, std::string(message)); + break; + case Severity::Notification: + LDEBUGC(category, std::string(message)); + break; + default: + throw ghoul::MissingCaseException(); + } + }; + ghoul::opengl::debug::setDebugCallback(callback); + } + LTRACE("OpenSpaceEngine::initializeGL::DebugContext(end)"); + } + + + LINFO("Initializing Rendering Engine"); + _renderEngine->initializeGL(); + + for (const auto& func : _moduleCallbacks.initializeGL) { + func(); + } + + LINFO("Finished initializing OpenGL"); + + LINFO("IsUsingSwapGroups: " << _windowWrapper->isUsingSwapGroups()); + LINFO("IsSwapGroupMaster: " << _windowWrapper->isSwapGroupMaster()); + + LTRACE("OpenSpaceEngine::initializeGL(end)"); +} + +double OpenSpaceEngine::runTime() { + return _runTime; +} + +void OpenSpaceEngine::setRunTime(double d) { + _runTime = d; +} + +void OpenSpaceEngine::preSynchronization() { + LTRACE("OpenSpaceEngine::preSynchronization(begin)"); + FileSys.triggerFilesystemEvents(); + + if (_scheduledSceneSwitch) { + loadScene(_scenePath); + _scheduledSceneSwitch = false; + } + + if (_isFirstRenderingFirstFrame) { + _windowWrapper->setSynchronization(false); + } + + bool master = _windowWrapper->isMaster(); + + _syncEngine->preSynchronization(SyncEngine::IsMaster(master)); + if (master) { + double dt = _windowWrapper->averageDeltaTime(); + _timeManager->preSynchronization(dt); + + using Iter = std::vector::const_iterator; + std::pair scheduledScripts = _scriptScheduler->progressTo( + timeManager().time().j2000Seconds() + ); + for (Iter it = scheduledScripts.first; it != scheduledScripts.second; ++it) { + _scriptEngine->queueScript( + *it, ScriptEngine::RemoteScripting::Yes + ); + } + + _interactionHandler->updateInputStates(dt); + + _renderEngine->updateScene(); + _interactionHandler->updateCamera(dt); + _renderEngine->camera()->invalidateCache(); + + _parallelConnection->preSynchronization(); + } + + for (const auto& func : _moduleCallbacks.preSync) { + func(); + } + LTRACE("OpenSpaceEngine::preSynchronization(end)"); +} + +void OpenSpaceEngine::postSynchronizationPreDraw() { + LTRACE("OpenSpaceEngine::postSynchronizationPreDraw(begin)"); + + bool master = _windowWrapper->isMaster(); + _syncEngine->postSynchronization(SyncEngine::IsMaster(master)); + + if (_shutdown.inShutdown) { + if (_shutdown.timer <= 0.f) { + _windowWrapper->terminate(); + } + _shutdown.timer -= static_cast(_windowWrapper->averageDeltaTime()); + } + + _renderEngine->updateScene(); + _renderEngine->updateFade(); + _renderEngine->updateRenderer(); + _renderEngine->updateScreenSpaceRenderables(); + _renderEngine->updateShaderPrograms(); + + if (!master) { + _renderEngine->camera()->invalidateCache(); + } + + // Step the camera using the current mouse velocities which are synced + //_interactionHandler->updateCamera(); + + for (const auto& func : _moduleCallbacks.postSyncPreDraw) { + func(); + } + + // Testing this every frame has minimal impact on the performance --- abock + // Debug build: 1-2 us ; Release build: <= 1 us + using ghoul::logging::LogManager; + int warningCounter = LogMgr.messageCounter(LogLevel::Warning); + int errorCounter = LogMgr.messageCounter(LogLevel::Error); + int fatalCounter = LogMgr.messageCounter(LogLevel::Fatal); + + if (warningCounter > 0) { + LWARNINGC("Logging", "Number of Warnings raised: " << warningCounter); + } + if (errorCounter > 0) { + LWARNINGC("Logging", "Number of Errors raised: " << errorCounter); + } + if (fatalCounter > 0) { + LWARNINGC("Logging", "Number of Fatals raised: " << fatalCounter); + } + + LogMgr.resetMessageCounters(); + + LTRACE("OpenSpaceEngine::postSynchronizationPreDraw(end)"); +} + +void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, + const glm::mat4& viewMatrix, + const glm::mat4& projectionMatrix) +{ + bool isGuiWindow = _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; + bool showOverlay = isGuiWindow && _windowWrapper->isMaster() && _windowWrapper->isRegularRendering(); + // @CLEANUP: Replace the two windows by a single call to whether a gui should be + // rendered ---abock + + if (showOverlay) { + _console->update(); + } + + LTRACE("OpenSpaceEngine::render(begin)"); + _renderEngine->render(sceneMatrix, viewMatrix, projectionMatrix); + + for (const auto& func : _moduleCallbacks.render) { + func(); + } + + if (showOverlay) { + _renderEngine->renderScreenLog(); + _console->render(); + } + + if (_shutdown.inShutdown) { + _renderEngine->renderShutdownInformation(_shutdown.timer, _shutdown.waitTime); + } + + LTRACE("OpenSpaceEngine::render(end)"); +} + +void OpenSpaceEngine::postDraw() { + LTRACE("OpenSpaceEngine::postDraw(begin)"); + + _renderEngine->postDraw(); + + for (const auto& func : _moduleCallbacks.postDraw) { + func(); + } + + if (_isFirstRenderingFirstFrame) { + _windowWrapper->setSynchronization(true); + _isFirstRenderingFirstFrame = false; + } + + LTRACE("OpenSpaceEngine::postDraw(end)"); +} + +void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction action) { + for (const auto& func : _moduleCallbacks.keyboard) { + const bool consumed = func(key, mod, action); + if (consumed) { + return; + } + } + + const bool consoleConsumed = _console->keyboardCallback(key, mod, action); + if (consoleConsumed) { + return; + } + + _interactionHandler->keyboardCallback(key, mod, action); +} + +void OpenSpaceEngine::charCallback(unsigned int codepoint, KeyModifier modifier) { + for (const auto& func : _moduleCallbacks.character) { + bool consumed = func(codepoint, modifier); + if (consumed) { + return; + } + } + + _console->charCallback(codepoint, modifier); +} + +void OpenSpaceEngine::mouseButtonCallback(MouseButton button, MouseAction action) { + for (const auto& func : _moduleCallbacks.mouseButton) { + bool consumed = func(button, action); + if (consumed) { + return; + } + } + + _interactionHandler->mouseButtonCallback(button, action); +} + +void OpenSpaceEngine::mousePositionCallback(double x, double y) { + for (const auto& func : _moduleCallbacks.mousePosition) { + func(x, y); + } + + _interactionHandler->mousePositionCallback(x, y); +} + +void OpenSpaceEngine::mouseScrollWheelCallback(double pos) { + for (const auto& func : _moduleCallbacks.mouseScrollWheel) { + bool consumed = func(pos); + if (consumed) { + return; + } + } + + _interactionHandler->mouseScrollWheelCallback(pos); +} + +void OpenSpaceEngine::encode() { + _syncEngine->encodeSyncables(); + + _networkEngine->publishStatusMessage(); + _networkEngine->sendMessages(); +} + +void OpenSpaceEngine::decode() { + _syncEngine->decodeSyncables(); +} + +void OpenSpaceEngine::externalControlCallback(const char* receivedChars, int size, + int clientId) +{ + if (size == 0) { + return; + } + + _networkEngine->handleMessage(std::string(receivedChars, size)); +} + +void OpenSpaceEngine::toggleShutdownMode() { + if (_shutdown.inShutdown) { + // If we are already in shutdown mode, we want to disable it + LINFO("Disabled shutdown mode"); + _shutdown.inShutdown = false; + } + else { + // Else, we have to enable it + LINFO("Shutting down OpenSpace"); + _shutdown.timer = _shutdown.waitTime; + _shutdown.inShutdown = true; + } +} + +scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { + return { + "", + { + { + "toggleShutdown", + &luascriptfunctions::toggleShutdown, + "", + "Toggles the shutdown mode that will close the application after the count" + "down timer is reached" + }, + { + "writeDocumentation", + &luascriptfunctions::writeDocumentation, + "", + "Writes out documentation files" + }, + { + "downloadFile", + &luascriptfunctions::downloadFile, + "", + "Downloads a file from Lua scope" + }, + { + "addVirtualProperty", + &luascriptfunctions::addVirtualProperty, + "type, name, identifier, [value, minimumValue, maximumValue]", + "Adds a virtual property that will set a group of properties" + }, + { + "removeVirtualProperty", + &luascriptfunctions::removeVirtualProperty, + "string", + "Removes a previously added virtual property" + }, + { + "removeAllVirtualProperties", + &luascriptfunctions::removeAllVirtualProperties, + "", + "Remove all registered virtual properties" + } + } + }; +} + +void OpenSpaceEngine::enableBarrier() { + _windowWrapper->setBarrier(true); +} + +void OpenSpaceEngine::disableBarrier() { + _windowWrapper->setBarrier(false); +} + +// Registers a callback for a specific CallbackOption +void OpenSpaceEngine::registerModuleCallback(OpenSpaceEngine::CallbackOption option, + std::function function) +{ + switch (option) { + case CallbackOption::Initialize: + _moduleCallbacks.initialize.push_back(std::move(function)); + break; + case CallbackOption::Deinitialize: + _moduleCallbacks.deinitialize.push_back(std::move(function)); + break; + case CallbackOption::InitializeGL: + _moduleCallbacks.initializeGL.push_back(std::move(function)); + break; + case CallbackOption::DeinitializeGL: + _moduleCallbacks.deinitializeGL.push_back(std::move(function)); + break; + case CallbackOption::PreSync: + _moduleCallbacks.preSync.push_back(std::move(function)); + break; + case CallbackOption::PostSyncPreDraw: + _moduleCallbacks.postSyncPreDraw.push_back(std::move(function)); + break; + case CallbackOption::Render: + _moduleCallbacks.render.push_back(std::move(function)); + break; + case CallbackOption::PostDraw: + _moduleCallbacks.postDraw.push_back(std::move(function)); + break; + default: + throw ghoul::MissingCaseException(); + } +} + +void OpenSpaceEngine::registerModuleKeyboardCallback( + std::function function) +{ + _moduleCallbacks.keyboard.push_back(std::move(function)); +} + +void OpenSpaceEngine::registerModuleCharCallback( + std::function function) +{ + _moduleCallbacks.character.push_back(std::move(function)); +} + +void OpenSpaceEngine::registerModuleMouseButtonCallback( + std::function function) +{ + _moduleCallbacks.mouseButton.push_back(std::move(function)); +} + +void OpenSpaceEngine::registerModuleMousePositionCallback( + std::function function) +{ + _moduleCallbacks.mousePosition.push_back(std::move(function)); +} + +void OpenSpaceEngine::registerModuleMouseScrollWheelCallback( + std::function function) +{ + _moduleCallbacks.mouseScrollWheel.push_back(std::move(function)); +} + +ConfigurationManager& OpenSpaceEngine::configurationManager() { + ghoul_assert(_configurationManager, "ConfigurationManager must not be nullptr"); + return *_configurationManager; +} + +LuaConsole& OpenSpaceEngine::console() { + ghoul_assert(_console, "LuaConsole must not be nullptr"); + return *_console; +} + +DownloadManager& OpenSpaceEngine::downloadManager() { + ghoul_assert(_downloadManager, "Download Manager must not be nullptr"); + return *_downloadManager; +} + +NetworkEngine& OpenSpaceEngine::networkEngine() { + ghoul_assert(_networkEngine, "NetworkEngine must not be nullptr"); + return *_networkEngine; +} + +ModuleEngine& OpenSpaceEngine::moduleEngine() { + ghoul_assert(_moduleEngine, "ModuleEngine must not be nullptr"); + return *_moduleEngine; +} + +ParallelConnection& OpenSpaceEngine::parallelConnection() { + ghoul_assert(_parallelConnection, "ParallelConnection must not be nullptr"); + return *_parallelConnection; +} + +RenderEngine& OpenSpaceEngine::renderEngine() { + ghoul_assert(_renderEngine, "RenderEngine must not be nullptr"); + return *_renderEngine; +} + +SettingsEngine& OpenSpaceEngine::settingsEngine() { + ghoul_assert(_settingsEngine, "Settings Engine must not be nullptr"); + return *_settingsEngine; +} + +TimeManager& OpenSpaceEngine::timeManager() { + ghoul_assert(_timeManager, "Download Manager must not be nullptr"); + return *_timeManager; +} + +WindowWrapper& OpenSpaceEngine::windowWrapper() { + ghoul_assert(_windowWrapper, "Window Wrapper must not be nullptr"); + return *_windowWrapper; +} + +ghoul::fontrendering::FontManager& OpenSpaceEngine::fontManager() { + ghoul_assert(_fontManager, "Font Manager must not be nullptr"); + return *_fontManager; +} + +interaction::InteractionHandler& OpenSpaceEngine::interactionHandler() { + ghoul_assert(_interactionHandler, "InteractionHandler must not be nullptr"); + return *_interactionHandler; +} + +properties::PropertyOwner& OpenSpaceEngine::globalPropertyOwner() { + ghoul_assert( + _globalPropertyNamespace, + "Global Property Namespace must not be nullptr" + ); + return *_globalPropertyNamespace; +} + +VirtualPropertyManager& OpenSpaceEngine::virtualPropertyManager() { + ghoul_assert( + _virtualPropertyManager, + "Virtual Property Manager must not be nullptr" + ); + + return *_virtualPropertyManager; +} + +ScriptEngine& OpenSpaceEngine::scriptEngine() { + ghoul_assert(_scriptEngine, "ScriptEngine must not be nullptr"); + return *_scriptEngine; +} + +ScriptScheduler& OpenSpaceEngine::scriptScheduler() { + ghoul_assert(_scriptScheduler, "ScriptScheduler must not be nullptr"); + return *_scriptScheduler; +} + +} // namespace openspace diff --git a/src/engine/wrapper/sgctwindowwrapper.cpp b/src/engine/wrapper/sgctwindowwrapper.cpp index c772b7863f..ef8f297808 100644 --- a/src/engine/wrapper/sgctwindowwrapper.cpp +++ b/src/engine/wrapper/sgctwindowwrapper.cpp @@ -1,248 +1,248 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include "sgct.h" - -#undef near -#undef far - -namespace { - const char* GuiWindowTag = "GUI"; -} // namespace - -namespace openspace { - -SGCTWindowWrapper::SGCTWindowWrapper() - : _eyeSeparation("eyeSeparation", "Eye Separation", 0.f, 0.f, 10.f) - , _showStatsGraph("showStatsGraph", "Show Stats Graph", false) -{ - _showStatsGraph.onChange([this](){ - sgct::Engine::instance()->setStatsGraphVisibility(_showStatsGraph); - }); - addProperty(_showStatsGraph); - - addProperty(_eyeSeparation); - _eyeSeparation.onChange([this](){ - setEyeSeparationDistance(_eyeSeparation); - }); -} - -void SGCTWindowWrapper::terminate() { - sgct::Engine::instance()->terminate(); -} - -void SGCTWindowWrapper::setBarrier(bool enabled) { - sgct::SGCTWindow::setBarrier(enabled); -} - -void SGCTWindowWrapper::setSynchronization(bool enabled) { - sgct_core::ClusterManager::instance()->setUseIgnoreSync(enabled); -} - -void SGCTWindowWrapper::clearAllWindows(const glm::vec4& clearColor) { - size_t n = sgct::Engine::instance()->getNumberOfWindows(); - for (size_t i = 0; i < n; ++i) { - glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - GLFWwindow* win = sgct::Engine::instance()->getWindowPtr(i)->getWindowHandle(); - glfwSwapBuffers(win); - } -} - -bool SGCTWindowWrapper::windowHasResized() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->isWindowResized(); -} - -double SGCTWindowWrapper::averageDeltaTime() const { - return sgct::Engine::instance()->getAvgDt(); -} - -double SGCTWindowWrapper::deltaTime() const { - return sgct::Engine::instance()->getDt(); -} - -glm::vec2 SGCTWindowWrapper::mousePosition() const { - int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); - double posX, posY; - sgct::Engine::instance()->getMousePos(id, &posX, &posY); - return glm::vec2(posX, posY); -} - -uint32_t SGCTWindowWrapper::mouseButtons(int maxNumber) const { - int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); - uint32_t result = 0; - for (int i = 0; i < maxNumber; ++i) { - bool button = (sgct::Engine::instance()->getMouseButton(id, i) != 0); - if (button) - result |= (1 << i); - - } - return result; -} - -glm::ivec2 SGCTWindowWrapper::currentWindowSize() const { - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - switch (window->getStereoMode()) { - case sgct::SGCTWindow::Side_By_Side_Stereo: - case sgct::SGCTWindow::Side_By_Side_Inverted_Stereo: - return glm::ivec2( - window->getXResolution() / 2, - window->getYResolution()); - case sgct::SGCTWindow::Top_Bottom_Stereo: - case sgct::SGCTWindow::Top_Bottom_Inverted_Stereo: - return glm::ivec2( - window->getXResolution(), - window->getYResolution() / 2); - default: - return glm::ivec2( - window->getXResolution(), - window->getYResolution()); - } -} - -glm::ivec2 SGCTWindowWrapper::currentWindowResolution() const { - int x, y; - auto window = sgct::Engine::instance()->getCurrentWindowPtr(); - window->getFinalFBODimensions(x, y); - return glm::ivec2(x, y); -} - -glm::ivec2 SGCTWindowWrapper::currentDrawBufferResolution() const { - sgct_core::Viewport* viewport = sgct::Engine::instance()->getCurrentWindowPtr()->getViewport(0); - if (viewport != nullptr){ - if (viewport->hasSubViewports() && viewport->getNonLinearProjectionPtr()) { - int res = viewport->getNonLinearProjectionPtr()->getCubemapResolution(); - return glm::ivec2(res, res); - } else { - return currentWindowResolution(); - } - } - throw WindowWrapperException("No viewport available"); -} - -glm::vec2 SGCTWindowWrapper::dpiScaling() const { - return glm::vec2( - sgct::Engine::instance()->getCurrentWindowPtr()->getXScale(), - sgct::Engine::instance()->getCurrentWindowPtr()->getYScale() - ); -} - -int SGCTWindowWrapper::currentNumberOfAaSamples() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfAASamples(); -} - -bool SGCTWindowWrapper::isRegularRendering() const { - sgct::SGCTWindow* w = sgct::Engine::instance()->getCurrentWindowPtr(); - std::size_t nViewports = w->getNumberOfViewports(); - (void)nViewports; // Unused in Release mode - ghoul_assert(nViewports > 0, "At least one viewport must exist at this time"); - sgct_core::Viewport* vp = w->getViewport(0); - sgct_core::NonLinearProjection* nlp = vp->getNonLinearProjectionPtr(); - return nlp == nullptr; -} - -bool SGCTWindowWrapper::hasGuiWindow() const { - auto engine = sgct::Engine::instance(); - for (size_t i = 0; i < engine->getNumberOfWindows(); ++i) { - if (engine->getWindowPtr(i)->checkIfTagExists(GuiWindowTag)) { - return true; - } - } - return false; -} - -bool SGCTWindowWrapper::isGuiWindow() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->checkIfTagExists( - GuiWindowTag - ); -} - -bool SGCTWindowWrapper::isMaster() const { - return sgct::Engine::instance()->isMaster(); -} - -bool SGCTWindowWrapper::isSwapGroupMaster() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->isSwapGroupMaster(); -} - -bool SGCTWindowWrapper::isUsingSwapGroups() const { - return sgct::Engine::instance()->getCurrentWindowPtr()->isUsingSwapGroups(); -} - -glm::mat4 SGCTWindowWrapper::viewProjectionMatrix() const { - return sgct::Engine::instance()->getCurrentModelViewProjectionMatrix(); -} - -glm::mat4 SGCTWindowWrapper::modelMatrix() const { - return sgct::Engine::instance()->getModelMatrix(); -} - -void SGCTWindowWrapper::setNearFarClippingPlane(float nearPlane, float farPlane) { - sgct::Engine::instance()->setNearAndFarClippingPlanes(nearPlane, farPlane); -} - -void SGCTWindowWrapper::setEyeSeparationDistance(float distance) { - sgct::Engine::instance()->setEyeSeparation(distance); -} - -glm::ivec4 SGCTWindowWrapper::viewportPixelCoordinates() const { - int x1, xSize, y1, ySize; - sgct::Engine::instance()->getCurrentWindowPtr()->getCurrentViewportPixelCoords(x1, - y1, - xSize, - ySize); - return glm::ivec4(x1, xSize, y1, ySize); -} - -bool SGCTWindowWrapper::isExternalControlConnected() const { - return sgct::Engine::instance()->isExternalControlConnected(); -} - -void SGCTWindowWrapper::sendMessageToExternalControl(const std::vector& message) const { - sgct::Engine::instance()->sendMessageToExternalControl( - message.data(), - static_cast(message.size()) - ); -} - -bool SGCTWindowWrapper::isSimpleRendering() const { - return (sgct::Engine::instance()->getCurrentRenderTarget() != sgct::Engine::NonLinearBuffer); - -} - -void SGCTWindowWrapper::takeScreenshot(bool applyWarping) const { - sgct::SGCTSettings::instance()->setCaptureFromBackBuffer(applyWarping); - sgct::Engine::instance()->takeScreenshot(); -} - -//void forEachWindow(std::function function) { -// size_t n = sgct::Engine::instance()->getNumberOfWindows(); -// for (size_t i = 0; i < n; ++i) -// function(); -//} - -} // namespace openspace - +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include "sgct.h" + +#undef near +#undef far + +namespace { + const char* GuiWindowTag = "GUI"; +} // namespace + +namespace openspace { + +SGCTWindowWrapper::SGCTWindowWrapper() + : _eyeSeparation("eyeSeparation", "Eye Separation", 0.f, 0.f, 10.f) + , _showStatsGraph("showStatsGraph", "Show Stats Graph", false) +{ + _showStatsGraph.onChange([this](){ + sgct::Engine::instance()->setStatsGraphVisibility(_showStatsGraph); + }); + addProperty(_showStatsGraph); + + addProperty(_eyeSeparation); + _eyeSeparation.onChange([this](){ + setEyeSeparationDistance(_eyeSeparation); + }); +} + +void SGCTWindowWrapper::terminate() { + sgct::Engine::instance()->terminate(); +} + +void SGCTWindowWrapper::setBarrier(bool enabled) { + sgct::SGCTWindow::setBarrier(enabled); +} + +void SGCTWindowWrapper::setSynchronization(bool enabled) { + sgct_core::ClusterManager::instance()->setUseIgnoreSync(enabled); +} + +void SGCTWindowWrapper::clearAllWindows(const glm::vec4& clearColor) { + size_t n = sgct::Engine::instance()->getNumberOfWindows(); + for (size_t i = 0; i < n; ++i) { + glClearColor(clearColor.r, clearColor.g, clearColor.b, clearColor.a); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GLFWwindow* win = sgct::Engine::instance()->getWindowPtr(i)->getWindowHandle(); + glfwSwapBuffers(win); + } +} + +bool SGCTWindowWrapper::windowHasResized() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->isWindowResized(); +} + +double SGCTWindowWrapper::averageDeltaTime() const { + return sgct::Engine::instance()->getAvgDt(); +} + +double SGCTWindowWrapper::deltaTime() const { + return sgct::Engine::instance()->getDt(); +} + +glm::vec2 SGCTWindowWrapper::mousePosition() const { + int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); + double posX, posY; + sgct::Engine::instance()->getMousePos(id, &posX, &posY); + return glm::vec2(posX, posY); +} + +uint32_t SGCTWindowWrapper::mouseButtons(int maxNumber) const { + int id = sgct::Engine::instance()->getCurrentWindowPtr()->getId(); + uint32_t result = 0; + for (int i = 0; i < maxNumber; ++i) { + bool button = (sgct::Engine::instance()->getMouseButton(id, i) != 0); + if (button) + result |= (1 << i); + + } + return result; +} + +glm::ivec2 SGCTWindowWrapper::currentWindowSize() const { + auto window = sgct::Engine::instance()->getCurrentWindowPtr(); + switch (window->getStereoMode()) { + case sgct::SGCTWindow::Side_By_Side_Stereo: + case sgct::SGCTWindow::Side_By_Side_Inverted_Stereo: + return glm::ivec2( + window->getXResolution() / 2, + window->getYResolution()); + case sgct::SGCTWindow::Top_Bottom_Stereo: + case sgct::SGCTWindow::Top_Bottom_Inverted_Stereo: + return glm::ivec2( + window->getXResolution(), + window->getYResolution() / 2); + default: + return glm::ivec2( + window->getXResolution(), + window->getYResolution()); + } +} + +glm::ivec2 SGCTWindowWrapper::currentWindowResolution() const { + int x, y; + auto window = sgct::Engine::instance()->getCurrentWindowPtr(); + window->getFinalFBODimensions(x, y); + return glm::ivec2(x, y); +} + +glm::ivec2 SGCTWindowWrapper::currentDrawBufferResolution() const { + sgct_core::Viewport* viewport = sgct::Engine::instance()->getCurrentWindowPtr()->getViewport(0); + if (viewport != nullptr){ + if (viewport->hasSubViewports() && viewport->getNonLinearProjectionPtr()) { + int res = viewport->getNonLinearProjectionPtr()->getCubemapResolution(); + return glm::ivec2(res, res); + } else { + return currentWindowResolution(); + } + } + throw WindowWrapperException("No viewport available"); +} + +glm::vec2 SGCTWindowWrapper::dpiScaling() const { + return glm::vec2( + sgct::Engine::instance()->getCurrentWindowPtr()->getXScale(), + sgct::Engine::instance()->getCurrentWindowPtr()->getYScale() + ); +} + +int SGCTWindowWrapper::currentNumberOfAaSamples() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->getNumberOfAASamples(); +} + +bool SGCTWindowWrapper::isRegularRendering() const { + sgct::SGCTWindow* w = sgct::Engine::instance()->getCurrentWindowPtr(); + std::size_t nViewports = w->getNumberOfViewports(); + (void)nViewports; // Unused in Release mode + ghoul_assert(nViewports > 0, "At least one viewport must exist at this time"); + sgct_core::Viewport* vp = w->getViewport(0); + sgct_core::NonLinearProjection* nlp = vp->getNonLinearProjectionPtr(); + return nlp == nullptr; +} + +bool SGCTWindowWrapper::hasGuiWindow() const { + auto engine = sgct::Engine::instance(); + for (size_t i = 0; i < engine->getNumberOfWindows(); ++i) { + if (engine->getWindowPtr(i)->checkIfTagExists(GuiWindowTag)) { + return true; + } + } + return false; +} + +bool SGCTWindowWrapper::isGuiWindow() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->checkIfTagExists( + GuiWindowTag + ); +} + +bool SGCTWindowWrapper::isMaster() const { + return sgct::Engine::instance()->isMaster(); +} + +bool SGCTWindowWrapper::isSwapGroupMaster() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->isSwapGroupMaster(); +} + +bool SGCTWindowWrapper::isUsingSwapGroups() const { + return sgct::Engine::instance()->getCurrentWindowPtr()->isUsingSwapGroups(); +} + +glm::mat4 SGCTWindowWrapper::viewProjectionMatrix() const { + return sgct::Engine::instance()->getCurrentModelViewProjectionMatrix(); +} + +glm::mat4 SGCTWindowWrapper::modelMatrix() const { + return sgct::Engine::instance()->getModelMatrix(); +} + +void SGCTWindowWrapper::setNearFarClippingPlane(float nearPlane, float farPlane) { + sgct::Engine::instance()->setNearAndFarClippingPlanes(nearPlane, farPlane); +} + +void SGCTWindowWrapper::setEyeSeparationDistance(float distance) { + sgct::Engine::instance()->setEyeSeparation(distance); +} + +glm::ivec4 SGCTWindowWrapper::viewportPixelCoordinates() const { + int x1, xSize, y1, ySize; + sgct::Engine::instance()->getCurrentWindowPtr()->getCurrentViewportPixelCoords(x1, + y1, + xSize, + ySize); + return glm::ivec4(x1, xSize, y1, ySize); +} + +bool SGCTWindowWrapper::isExternalControlConnected() const { + return sgct::Engine::instance()->isExternalControlConnected(); +} + +void SGCTWindowWrapper::sendMessageToExternalControl(const std::vector& message) const { + sgct::Engine::instance()->sendMessageToExternalControl( + message.data(), + static_cast(message.size()) + ); +} + +bool SGCTWindowWrapper::isSimpleRendering() const { + return (sgct::Engine::instance()->getCurrentRenderTarget() != sgct::Engine::NonLinearBuffer); + +} + +void SGCTWindowWrapper::takeScreenshot(bool applyWarping) const { + sgct::SGCTSettings::instance()->setCaptureFromBackBuffer(applyWarping); + sgct::Engine::instance()->takeScreenshot(); +} + +//void forEachWindow(std::function function) { +// size_t n = sgct::Engine::instance()->getNumberOfWindows(); +// for (size_t i = 0; i < n; ++i) +// function(); +//} + +} // namespace openspace + diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 4802b6f892..6acfcb5c32 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -1,528 +1,528 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -namespace { - const char* _loggerCat = "FramebufferRenderer"; - const char* ExitFragmentShaderPath = "${SHADERS}/framebuffer/exitframebuffer.frag"; - const char* RaycastFragmentShaderPath = "${SHADERS}/framebuffer/raycastframebuffer.frag"; - const char* GetEntryInsidePath = "${SHADERS}/framebuffer/inside.glsl"; - const char* GetEntryOutsidePath = "${SHADERS}/framebuffer/outside.glsl"; - const char* RenderFragmentShaderPath = "${SHADERS}/framebuffer/renderframebuffer.frag"; -} // namespace - -namespace openspace { - -FramebufferRenderer::FramebufferRenderer() - : _camera(nullptr) - , _scene(nullptr) - , _resolution(glm::vec2(0)) -{} - -FramebufferRenderer::~FramebufferRenderer() {} - -void FramebufferRenderer::initialize() { - LINFO("Initializing FramebufferRenderer"); - - const GLfloat size = 1.0f; - const GLfloat vertex_data[] = { - // x y s t - -size, -size, 0.0f, 1.0f, - size, size, 0.0f, 1.0f, - -size, size, 0.0f, 1.0f, - -size, -size, 0.0f, 1.0f, - size, -size, 0.0f, 1.0f, - size, size, 0.0f, 1.0f - }; - - glGenVertexArrays(1, &_screenQuad); - glBindVertexArray(_screenQuad); - - glGenBuffers(1, &_vertexPositionBuffer); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); - glVertexAttribPointer( - 0, - 4, - GL_FLOAT, - GL_FALSE, - sizeof(GLfloat) * 4, - reinterpret_cast(0) - ); - glEnableVertexAttribArray(0); - - GLint defaultFbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); - - // Main framebuffer - glGenTextures(1, &_mainColorTexture); - glGenTextures(1, &_mainDepthTexture); - glGenFramebuffers(1, &_mainFramebuffer); - - // Exit framebuffer - glGenTextures(1, &_exitColorTexture); - glGenTextures(1, &_exitDepthTexture); - glGenFramebuffers(1, &_exitFramebuffer); - - updateResolution(); - updateRendererData(); - updateRaycastData(); - - glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D_MULTISAMPLE, - _mainColorTexture, - 0 - ); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D_MULTISAMPLE, - _mainDepthTexture, - 0 - ); - - glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - _exitColorTexture, - 0 - ); - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_DEPTH_ATTACHMENT, - GL_TEXTURE_2D, - _exitDepthTexture, - 0 - ); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - LERROR("Main framebuffer is not complete"); - } - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); - - try { - _resolveProgram = ghoul::opengl::ProgramObject::Build( - "Framebuffer Resolve", - "${SHADERS}/framebuffer/resolveframebuffer.vert", - "${SHADERS}/framebuffer/resolveframebuffer.frag" - ); - } catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - - OsEng.renderEngine().raycasterManager().addListener(*this); -} - -void FramebufferRenderer::deinitialize() { - LINFO("Deinitializing FramebufferRenderer"); - - glDeleteFramebuffers(1, &_mainFramebuffer); - glDeleteFramebuffers(1, &_exitFramebuffer); - - glDeleteTextures(1, &_mainColorTexture); - glDeleteTextures(1, &_mainDepthTexture); - glDeleteTextures(1, &_exitColorTexture); - glDeleteTextures(1, &_exitDepthTexture); - - glDeleteBuffers(1, &_vertexPositionBuffer); - glDeleteVertexArrays(1, &_screenQuad); - - OsEng.renderEngine().raycasterManager().removeListener(*this); -} - -void FramebufferRenderer::raycastersChanged(VolumeRaycaster&, bool) { - _dirtyRaycastData = true; -} - -void FramebufferRenderer::update() { - if (_dirtyResolution) { - updateResolution(); - } - - if (_dirtyRaycastData) { - updateRaycastData(); - } - - // If the resolve dictionary changed (or a file changed on disk) - // then rebuild the resolve program. - if (_resolveProgram->isDirty()) { - try { - _resolveProgram->rebuildFromFile(); - } catch (const ghoul::RuntimeError& error) { - LERRORC(error.component, error.message); - } - } - - for (auto& program : _exitPrograms) { - if (program.second->isDirty()) { - try { - program.second->rebuildFromFile(); - } catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - } - - for (auto& program : _raycastPrograms) { - if (program.second->isDirty()) { - try { - program.second->rebuildFromFile(); - } catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - } - - for (auto& program : _insideRaycastPrograms) { - if (program.second->isDirty()) { - try { - program.second->rebuildFromFile(); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - } -} - -void FramebufferRenderer::updateResolution() { - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); - - glTexImage2DMultisample( - GL_TEXTURE_2D_MULTISAMPLE, - _nAaSamples, - GL_RGBA, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - true - ); - - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); - glTexImage2DMultisample( - GL_TEXTURE_2D_MULTISAMPLE, - _nAaSamples, - GL_DEPTH_COMPONENT32F, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - true - ); - - glBindTexture(GL_TEXTURE_2D, _exitColorTexture); - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_RGBA16, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - 0, - GL_RGBA, - GL_UNSIGNED_SHORT, - nullptr - ); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); - - glTexImage2D( - GL_TEXTURE_2D, - 0, - GL_DEPTH_COMPONENT32F, - GLsizei(_resolution.x), - GLsizei(_resolution.y), - 0, - GL_DEPTH_COMPONENT, - GL_FLOAT, - nullptr - ); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - _dirtyResolution = false; -} - -void FramebufferRenderer::updateRaycastData() { - _raycastData.clear(); - _exitPrograms.clear(); - _raycastPrograms.clear(); - _insideRaycastPrograms.clear(); - - const std::vector& raycasters = - OsEng.renderEngine().raycasterManager().raycasters(); - int nextId = 0; - for (auto& raycaster : raycasters) { - RaycastData data; - data.id = nextId++; - data.namespaceName = "HELPER"; - - std::string vsPath = raycaster->getBoundsVsPath(); - std::string fsPath = raycaster->getBoundsFsPath(); - - ghoul::Dictionary dict; - dict.setValue("rendererData", _rendererData); - dict.setValue("fragmentPath", fsPath); - dict.setValue("id", data.id); - std::string helperPath = raycaster->getHelperPath(); - ghoul::Dictionary helpersDict; - if (!helperPath.empty()) { - helpersDict.setValue("0", helperPath); - } - dict.setValue("helperPaths", helpersDict); - dict.setValue("raycastPath", raycaster->getRaycastPath()); - - _raycastData[raycaster] = data; - - try { - _exitPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( - "Volume " + std::to_string(data.id) + " exit", - vsPath, - ExitFragmentShaderPath, - dict - ); - } catch (ghoul::RuntimeError e) { - LERROR(e.message); - } - try { - ghoul::Dictionary outsideDict = dict; - outsideDict.setValue("getEntryPath", GetEntryOutsidePath); - _raycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( - "Volume " + std::to_string(data.id) + " raycast", - vsPath, - RaycastFragmentShaderPath, - outsideDict - ); - } catch (ghoul::RuntimeError e) { - LERROR(e.message); - } - try { - ghoul::Dictionary insideDict = dict; - insideDict.setValue("getEntryPath", GetEntryInsidePath); - _insideRaycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( - "Volume " + std::to_string(data.id) + " inside raycast", - "${SHADERS}/framebuffer/resolveframebuffer.vert", - RaycastFragmentShaderPath, - insideDict - ); - } - catch (const ghoul::RuntimeError& e) { - LERRORC(e.component, e.message); - } - } - _dirtyRaycastData = false; -} - -void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { - std::unique_ptr perf; - if (doPerformanceMeasurements) { - perf = std::make_unique( - "FramebufferRenderer::render", - OsEng.renderEngine().performanceManager() - ); - } - - if (!_scene || !_camera) { - return; - } - - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - Time time = OsEng.timeManager().time(); - - RenderData data = { *_camera, psc(), time, doPerformanceMeasurements, 0 }; - RendererTasks tasks; - - // Capture standard fbo - GLint defaultFbo; - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); - - glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - data.renderBinMask = static_cast(Renderable::RenderBin::Background); - _scene->render(data, tasks); - data.renderBinMask = static_cast(Renderable::RenderBin::Opaque); - _scene->render(data, tasks); - data.renderBinMask = static_cast(Renderable::RenderBin::Transparent); - _scene->render(data, tasks); - data.renderBinMask = static_cast(Renderable::RenderBin::Overlay); - _scene->render(data, tasks); - - for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { - VolumeRaycaster* raycaster = raycasterTask.raycaster; - - glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - ghoul::opengl::ProgramObject* exitProgram = _exitPrograms[raycaster].get(); - if (exitProgram) { - exitProgram->activate(); - raycaster->renderExitPoints(raycasterTask.renderData, *exitProgram); - exitProgram->deactivate(); - } - - glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); - glm::vec3 cameraPosition; - bool cameraIsInside = raycaster->cameraIsInside( - raycasterTask.renderData, - cameraPosition - ); - ghoul::opengl::ProgramObject* raycastProgram = nullptr; - - if (cameraIsInside) { - raycastProgram = _insideRaycastPrograms[raycaster].get(); - if (raycastProgram) { - raycastProgram->activate(); - raycastProgram->setUniform("cameraPosInRaycaster", cameraPosition); - } - } else { - raycastProgram = _raycastPrograms[raycaster].get(); - if (raycastProgram) { - raycastProgram->activate(); - } - } - - if (raycastProgram) { - raycaster->preRaycast(_raycastData[raycaster], *raycastProgram); - - ghoul::opengl::TextureUnit exitColorTextureUnit; - exitColorTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D, _exitColorTexture); - raycastProgram->setUniform("exitColorTexture", exitColorTextureUnit); - - ghoul::opengl::TextureUnit exitDepthTextureUnit; - exitDepthTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); - raycastProgram->setUniform("exitDepthTexture", exitDepthTextureUnit); - - ghoul::opengl::TextureUnit mainDepthTextureUnit; - mainDepthTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); - raycastProgram->setUniform("mainDepthTexture", mainDepthTextureUnit); - - raycastProgram->setUniform("nAaSamples", _nAaSamples); - raycastProgram->setUniform("windowSize", glm::vec2(_resolution)); - - - glDisable(GL_DEPTH_TEST); - glDepthMask(false); - if (cameraIsInside) { - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - } else { - raycaster->renderEntryPoints(raycasterTask.renderData, *raycastProgram); - } - glDepthMask(true); - glEnable(GL_DEPTH_TEST); - - raycaster->postRaycast(_raycastData[raycaster], *raycastProgram); - raycastProgram->deactivate(); - } else { - LWARNING("Raycaster is not attached when trying to perform raycaster task"); - } - } - - glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); - _resolveProgram->activate(); - - ghoul::opengl::TextureUnit mainColorTextureUnit; - mainColorTextureUnit.activate(); - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); - - _resolveProgram->setUniform("mainColorTexture", mainColorTextureUnit); - _resolveProgram->setUniform("blackoutFactor", blackoutFactor); - _resolveProgram->setUniform("nAaSamples", _nAaSamples); - glBindVertexArray(_screenQuad); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); - - _resolveProgram->deactivate(); -} - -void FramebufferRenderer::setScene(Scene* scene) { - _scene = scene; -} - -void FramebufferRenderer::setCamera(Camera* camera) { - _camera = camera; -} - -void FramebufferRenderer::setResolution(glm::ivec2 res) { - _resolution = res; - _dirtyResolution = true; -} - -void FramebufferRenderer::setNAaSamples(int nAaSamples) { - _nAaSamples = nAaSamples; - if (_nAaSamples == 0) { - _nAaSamples = 1; - } - if (_nAaSamples > 8) { - LERROR("Framebuffer renderer does not support more than 8 MSAA samples."); - _nAaSamples = 8; - } - _dirtyResolution = true; -} - -void FramebufferRenderer::updateRendererData() { - ghoul::Dictionary dict; - dict.setValue("fragmentRendererPath", std::string(RenderFragmentShaderPath)); - - _rendererData = dict; - - OsEng.renderEngine().setRendererData(dict); -} - -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + const char* _loggerCat = "FramebufferRenderer"; + const char* ExitFragmentShaderPath = "${SHADERS}/framebuffer/exitframebuffer.frag"; + const char* RaycastFragmentShaderPath = "${SHADERS}/framebuffer/raycastframebuffer.frag"; + const char* GetEntryInsidePath = "${SHADERS}/framebuffer/inside.glsl"; + const char* GetEntryOutsidePath = "${SHADERS}/framebuffer/outside.glsl"; + const char* RenderFragmentShaderPath = "${SHADERS}/framebuffer/renderframebuffer.frag"; +} // namespace + +namespace openspace { + +FramebufferRenderer::FramebufferRenderer() + : _camera(nullptr) + , _scene(nullptr) + , _resolution(glm::vec2(0)) +{} + +FramebufferRenderer::~FramebufferRenderer() {} + +void FramebufferRenderer::initialize() { + LINFO("Initializing FramebufferRenderer"); + + const GLfloat size = 1.0f; + const GLfloat vertex_data[] = { + // x y s t + -size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f, + -size, size, 0.0f, 1.0f, + -size, -size, 0.0f, 1.0f, + size, -size, 0.0f, 1.0f, + size, size, 0.0f, 1.0f + }; + + glGenVertexArrays(1, &_screenQuad); + glBindVertexArray(_screenQuad); + + glGenBuffers(1, &_vertexPositionBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); + + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glVertexAttribPointer( + 0, + 4, + GL_FLOAT, + GL_FALSE, + sizeof(GLfloat) * 4, + reinterpret_cast(0) + ); + glEnableVertexAttribArray(0); + + GLint defaultFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); + + // Main framebuffer + glGenTextures(1, &_mainColorTexture); + glGenTextures(1, &_mainDepthTexture); + glGenFramebuffers(1, &_mainFramebuffer); + + // Exit framebuffer + glGenTextures(1, &_exitColorTexture); + glGenTextures(1, &_exitDepthTexture); + glGenFramebuffers(1, &_exitFramebuffer); + + updateResolution(); + updateRendererData(); + updateRaycastData(); + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D_MULTISAMPLE, + _mainColorTexture, + 0 + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D_MULTISAMPLE, + _mainDepthTexture, + 0 + ); + + glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + _exitColorTexture, + 0 + ); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, + _exitDepthTexture, + 0 + ); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Main framebuffer is not complete"); + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + + try { + _resolveProgram = ghoul::opengl::ProgramObject::Build( + "Framebuffer Resolve", + "${SHADERS}/framebuffer/resolveframebuffer.vert", + "${SHADERS}/framebuffer/resolveframebuffer.frag" + ); + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + + OsEng.renderEngine().raycasterManager().addListener(*this); +} + +void FramebufferRenderer::deinitialize() { + LINFO("Deinitializing FramebufferRenderer"); + + glDeleteFramebuffers(1, &_mainFramebuffer); + glDeleteFramebuffers(1, &_exitFramebuffer); + + glDeleteTextures(1, &_mainColorTexture); + glDeleteTextures(1, &_mainDepthTexture); + glDeleteTextures(1, &_exitColorTexture); + glDeleteTextures(1, &_exitDepthTexture); + + glDeleteBuffers(1, &_vertexPositionBuffer); + glDeleteVertexArrays(1, &_screenQuad); + + OsEng.renderEngine().raycasterManager().removeListener(*this); +} + +void FramebufferRenderer::raycastersChanged(VolumeRaycaster&, bool) { + _dirtyRaycastData = true; +} + +void FramebufferRenderer::update() { + if (_dirtyResolution) { + updateResolution(); + } + + if (_dirtyRaycastData) { + updateRaycastData(); + } + + // If the resolve dictionary changed (or a file changed on disk) + // then rebuild the resolve program. + if (_resolveProgram->isDirty()) { + try { + _resolveProgram->rebuildFromFile(); + } catch (const ghoul::RuntimeError& error) { + LERRORC(error.component, error.message); + } + } + + for (auto& program : _exitPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + } + + for (auto& program : _raycastPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + } + + for (auto& program : _insideRaycastPrograms) { + if (program.second->isDirty()) { + try { + program.second->rebuildFromFile(); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + } +} + +void FramebufferRenderer::updateResolution() { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); + + glTexImage2DMultisample( + GL_TEXTURE_2D_MULTISAMPLE, + _nAaSamples, + GL_RGBA, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + true + ); + + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); + glTexImage2DMultisample( + GL_TEXTURE_2D_MULTISAMPLE, + _nAaSamples, + GL_DEPTH_COMPONENT32F, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + true + ); + + glBindTexture(GL_TEXTURE_2D, _exitColorTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA16, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + 0, + GL_RGBA, + GL_UNSIGNED_SHORT, + nullptr + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_DEPTH_COMPONENT32F, + GLsizei(_resolution.x), + GLsizei(_resolution.y), + 0, + GL_DEPTH_COMPONENT, + GL_FLOAT, + nullptr + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + _dirtyResolution = false; +} + +void FramebufferRenderer::updateRaycastData() { + _raycastData.clear(); + _exitPrograms.clear(); + _raycastPrograms.clear(); + _insideRaycastPrograms.clear(); + + const std::vector& raycasters = + OsEng.renderEngine().raycasterManager().raycasters(); + int nextId = 0; + for (auto& raycaster : raycasters) { + RaycastData data; + data.id = nextId++; + data.namespaceName = "HELPER"; + + std::string vsPath = raycaster->getBoundsVsPath(); + std::string fsPath = raycaster->getBoundsFsPath(); + + ghoul::Dictionary dict; + dict.setValue("rendererData", _rendererData); + dict.setValue("fragmentPath", fsPath); + dict.setValue("id", data.id); + std::string helperPath = raycaster->getHelperPath(); + ghoul::Dictionary helpersDict; + if (!helperPath.empty()) { + helpersDict.setValue("0", helperPath); + } + dict.setValue("helperPaths", helpersDict); + dict.setValue("raycastPath", raycaster->getRaycastPath()); + + _raycastData[raycaster] = data; + + try { + _exitPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( + "Volume " + std::to_string(data.id) + " exit", + vsPath, + ExitFragmentShaderPath, + dict + ); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + try { + ghoul::Dictionary outsideDict = dict; + outsideDict.setValue("getEntryPath", GetEntryOutsidePath); + _raycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( + "Volume " + std::to_string(data.id) + " raycast", + vsPath, + RaycastFragmentShaderPath, + outsideDict + ); + } catch (ghoul::RuntimeError e) { + LERROR(e.message); + } + try { + ghoul::Dictionary insideDict = dict; + insideDict.setValue("getEntryPath", GetEntryInsidePath); + _insideRaycastPrograms[raycaster] = ghoul::opengl::ProgramObject::Build( + "Volume " + std::to_string(data.id) + " inside raycast", + "${SHADERS}/framebuffer/resolveframebuffer.vert", + RaycastFragmentShaderPath, + insideDict + ); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } + } + _dirtyRaycastData = false; +} + +void FramebufferRenderer::render(float blackoutFactor, bool doPerformanceMeasurements) { + std::unique_ptr perf; + if (doPerformanceMeasurements) { + perf = std::make_unique( + "FramebufferRenderer::render", + OsEng.renderEngine().performanceManager() + ); + } + + if (!_scene || !_camera) { + return; + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Time time = OsEng.timeManager().time(); + + RenderData data = { *_camera, psc(), time, doPerformanceMeasurements, 0 }; + RendererTasks tasks; + + // Capture standard fbo + GLint defaultFbo; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbo); + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + data.renderBinMask = static_cast(Renderable::RenderBin::Background); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Opaque); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Transparent); + _scene->render(data, tasks); + data.renderBinMask = static_cast(Renderable::RenderBin::Overlay); + _scene->render(data, tasks); + + for (const RaycasterTask& raycasterTask : tasks.raycasterTasks) { + VolumeRaycaster* raycaster = raycasterTask.raycaster; + + glBindFramebuffer(GL_FRAMEBUFFER, _exitFramebuffer); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + ghoul::opengl::ProgramObject* exitProgram = _exitPrograms[raycaster].get(); + if (exitProgram) { + exitProgram->activate(); + raycaster->renderExitPoints(raycasterTask.renderData, *exitProgram); + exitProgram->deactivate(); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _mainFramebuffer); + glm::vec3 cameraPosition; + bool cameraIsInside = raycaster->cameraIsInside( + raycasterTask.renderData, + cameraPosition + ); + ghoul::opengl::ProgramObject* raycastProgram = nullptr; + + if (cameraIsInside) { + raycastProgram = _insideRaycastPrograms[raycaster].get(); + if (raycastProgram) { + raycastProgram->activate(); + raycastProgram->setUniform("cameraPosInRaycaster", cameraPosition); + } + } else { + raycastProgram = _raycastPrograms[raycaster].get(); + if (raycastProgram) { + raycastProgram->activate(); + } + } + + if (raycastProgram) { + raycaster->preRaycast(_raycastData[raycaster], *raycastProgram); + + ghoul::opengl::TextureUnit exitColorTextureUnit; + exitColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _exitColorTexture); + raycastProgram->setUniform("exitColorTexture", exitColorTextureUnit); + + ghoul::opengl::TextureUnit exitDepthTextureUnit; + exitDepthTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D, _exitDepthTexture); + raycastProgram->setUniform("exitDepthTexture", exitDepthTextureUnit); + + ghoul::opengl::TextureUnit mainDepthTextureUnit; + mainDepthTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainDepthTexture); + raycastProgram->setUniform("mainDepthTexture", mainDepthTextureUnit); + + raycastProgram->setUniform("nAaSamples", _nAaSamples); + raycastProgram->setUniform("windowSize", glm::vec2(_resolution)); + + + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + if (cameraIsInside) { + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + } else { + raycaster->renderEntryPoints(raycasterTask.renderData, *raycastProgram); + } + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + + raycaster->postRaycast(_raycastData[raycaster], *raycastProgram); + raycastProgram->deactivate(); + } else { + LWARNING("Raycaster is not attached when trying to perform raycaster task"); + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); + _resolveProgram->activate(); + + ghoul::opengl::TextureUnit mainColorTextureUnit; + mainColorTextureUnit.activate(); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainColorTexture); + + _resolveProgram->setUniform("mainColorTexture", mainColorTextureUnit); + _resolveProgram->setUniform("blackoutFactor", blackoutFactor); + _resolveProgram->setUniform("nAaSamples", _nAaSamples); + glBindVertexArray(_screenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + _resolveProgram->deactivate(); +} + +void FramebufferRenderer::setScene(Scene* scene) { + _scene = scene; +} + +void FramebufferRenderer::setCamera(Camera* camera) { + _camera = camera; +} + +void FramebufferRenderer::setResolution(glm::ivec2 res) { + _resolution = res; + _dirtyResolution = true; +} + +void FramebufferRenderer::setNAaSamples(int nAaSamples) { + _nAaSamples = nAaSamples; + if (_nAaSamples == 0) { + _nAaSamples = 1; + } + if (_nAaSamples > 8) { + LERROR("Framebuffer renderer does not support more than 8 MSAA samples."); + _nAaSamples = 8; + } + _dirtyResolution = true; +} + +void FramebufferRenderer::updateRendererData() { + ghoul::Dictionary dict; + dict.setValue("fragmentRendererPath", std::string(RenderFragmentShaderPath)); + + _rendererData = dict; + + OsEng.renderEngine().setRendererData(dict); +} + +} // namespace openspace diff --git a/src/util/syncbuffer.cpp b/src/util/syncbuffer.cpp index 593012be92..3e2499ab81 100644 --- a/src/util/syncbuffer.cpp +++ b/src/util/syncbuffer.cpp @@ -1,62 +1,62 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include - -namespace openspace { - -SyncBuffer::SyncBuffer(size_t n) - : _n(n) - , _encodeOffset(0) - , _decodeOffset(0) - , _synchronizationBuffer(new sgct::SharedVector()) -{ - _dataStream.resize(_n); -} - -SyncBuffer::~SyncBuffer() { - // The destructor is defined here, so that the otherwise default inlined destructor is - // not created (which would make it impossible to use a forward declaration with - // unique_ptr -} - -void SyncBuffer::write() { - _dataStream.resize(_encodeOffset); - _synchronizationBuffer->setVal(_dataStream); - sgct::SharedData::instance()->writeVector(_synchronizationBuffer.get()); - _dataStream.resize(_n); - _encodeOffset = 0; - _decodeOffset = 0; -} - -void SyncBuffer::read() { - sgct::SharedData::instance()->readVector(_synchronizationBuffer.get()); - _dataStream = _synchronizationBuffer->getVal(); - _encodeOffset = 0; - _decodeOffset = 0; -} - -} // namespace openspace +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace openspace { + +SyncBuffer::SyncBuffer(size_t n) + : _n(n) + , _encodeOffset(0) + , _decodeOffset(0) + , _synchronizationBuffer(new sgct::SharedVector()) +{ + _dataStream.resize(_n); +} + +SyncBuffer::~SyncBuffer() { + // The destructor is defined here, so that the otherwise default inlined destructor is + // not created (which would make it impossible to use a forward declaration with + // unique_ptr +} + +void SyncBuffer::write() { + _dataStream.resize(_encodeOffset); + _synchronizationBuffer->setVal(_dataStream); + sgct::SharedData::instance()->writeVector(_synchronizationBuffer.get()); + _dataStream.resize(_n); + _encodeOffset = 0; + _decodeOffset = 0; +} + +void SyncBuffer::read() { + sgct::SharedData::instance()->readVector(_synchronizationBuffer.get()); + _dataStream = _synchronizationBuffer->getVal(); + _encodeOffset = 0; + _decodeOffset = 0; +} + +} // namespace openspace diff --git a/support/cmake/support_macros.cmake b/support/cmake/support_macros.cmake index 9e895cd903..cc58e7e47d 100644 --- a/support/cmake/support_macros.cmake +++ b/support/cmake/support_macros.cmake @@ -1,534 +1,564 @@ -######################################################################################### -# # -# OpenSpace # -# # -# Copyright (c) 2014-2017 # -# # -# Permission is hereby granted, free of charge, to any person obtaining a copy of this # -# software and associated documentation files (the "Software"), to deal in the Software # -# without restriction, including without limitation the rights to use, copy, modify, # -# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # -# permit persons to whom the Software is furnished to do so, subject to the following # -# conditions: # -# # -# The above copyright notice and this permission notice shall be included in all copies # -# or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # -# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # -# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # -# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE # -# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -######################################################################################### - -function (test_compiler_compatibility) - if (MSVC) - if (MSVC_VERSION LESS 1900) - message(FATAL_ERROR "OpenSpace requires at least Visual Studio 2015") - endif () - endif () -endfunction () - - - -macro (cleanup_project) - # Remove MinSizeRel build option - set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE TYPE INTERNAL FORCE) - mark_as_advanced(CMAKE_CONFIGURATION_TYPES) - mark_as_advanced(CMAKE_INSTALL_PREFIX) - - set_property(GLOBAL PROPERTY USE_FOLDERS On) - set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER CMake) -endmacro () - - -macro (set_build_output_directories) - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OPENSPACE_CMAKE_EXT_DIR}) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/openspace) -endmacro () - - - -function (create_openspace_target) - add_library(libOpenSpace STATIC ${OPENSPACE_HEADER} ${OPENSPACE_SOURCE}) - target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}/include) - target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}) - target_include_directories(libOpenSpace PUBLIC ${CMAKE_BINARY_DIR}/_generated/include) - - configure_file( - ${OPENSPACE_CMAKE_EXT_DIR}/openspace_header.template - ${CMAKE_BINARY_DIR}/_generated/include/openspace/openspace.h - @ONLY IMMEDIATE - ) - - set_compile_settings(libOpenSpace) -endfunction () - - - -function (set_compile_settings project) - set_property(TARGET ${project} PROPERTY CXX_STANDARD 17) - set_property(TARGET ${project} PROPERTY CXX_STANDARD_REQUIRED On) - - if (MSVC) - target_compile_options(${project} PRIVATE - "/MP" # Multi-threading support - "/W4" # Enable all warnings - "/ZI" # Edit and continue support - "/wd4201" # Disable "nameless struct" warning - "/wd4127" # Disable "conditional expression is constant" warning - "/permissive-" # Disable working, but non-conforming code - "/Zc:strictStrings-" # Windows header don't adhere to this - # "/std:c++latest" # Boost as of 1.64 still uses unary_function - ) - if (OPENSPACE_WARNINGS_AS_ERRORS) - target_compile_options(${project} PRIVATE "/WX") - endif () - elseif (APPLE) - target_compile_definitions(${project} PRIVATE "__APPLE__") - - if (OPENSPACE_WARNINGS_AS_ERRORS) - target_compile_options(${project} PRIVATE "-Werror") - endif () - - target_compile_options(${project} PRIVATE "-stdlib=libc++") - - target_include_directories(${project} PUBLIC "/Developer/Headers/FlatCarbon") - find_library(COREFOUNDATION_LIBRARY CoreFoundation) - find_library(CARBON_LIBRARY Carbon) - find_library(COCOA_LIBRARY Carbon) - find_library(APP_SERVICES_LIBRARY ApplicationServices) - mark_as_advanced(CARBON_LIBRARY COCOA_LIBRARY APP_SERVICES_LIBRARY) - target_link_libraries(${project} - ${CARBON_LIBRARY} - ${COREFOUNDATION_LIBRARY} - ${COCOA_LIBRARY} - ${APP_SERVICES_LIBRARY} - ) - elseif (UNIX) - target_compile_options(${project} PRIVATE "-ggdb" "-Wall" "-Wno-long-long" "-pedantic" "-Wextra") - - if (OPENSPACE_WARNINGS_AS_ERRORS) - target_compile_options(${project} PRIVATE "-Werror") - endif () - endif () -endfunction () - - - -function (add_external_dependencies) - # Ghoul - add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul) - target_link_libraries(libOpenSpace Ghoul) - get_property(GHOUL_INCLUDE_DIR TARGET Ghoul PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - target_include_directories(libOpenSpace PUBLIC ${GHOUL_INCLUDE_DIR}) - get_property(GHOUL_DEFINITIONS TARGET Ghoul PROPERTY INTERFACE_COMPILE_DEFINITIONS) - target_compile_definitions(libOpenSpace PUBLIC ${GHOUL_DEFINITIONS}) - set_property(TARGET Lua PROPERTY FOLDER "External") - set_property(TARGET lz4 PROPERTY FOLDER "External") - - # SGCT - set(SGCT_TEXT OFF CACHE BOOL "" FORCE) - set(SGCT_BUILD_CSHARP_PROJECTS OFF CACHE BOOL "" FORCE) - set(SGCT_LIGHT_ONLY ON CACHE BOOL "" FORCE) - set(SGCT_CUSTOMOUTPUTDIRS OFF CACHE BOOL "" FORCE) - - add_subdirectory(${OPENSPACE_EXT_DIR}/sgct) - target_include_directories(libOpenSpace SYSTEM PUBLIC ${OPENSPACE_EXT_DIR}/sgct/include) - target_link_libraries( - libOpenSpace - # sgct - sgct_light glew glfw png16_static quat tinyxml2static turbojpeg-static - vrpn - ${GLFW_LIBRARIES} - ) - - set_property(TARGET sgct_light PROPERTY FOLDER "External") - set_property(TARGET glew PROPERTY FOLDER "External/SGCT") - set_property(TARGET glfw PROPERTY FOLDER "External/SGCT") - set_property(TARGET png16_static PROPERTY FOLDER "External/SGCT") - set_property(TARGET quat PROPERTY FOLDER "External/SGCT") - set_property(TARGET simd PROPERTY FOLDER "External/SGCT") - set_property(TARGET tinyxml2static PROPERTY FOLDER "External/SGCT") - set_property(TARGET turbojpeg-static PROPERTY FOLDER "External/SGCT") - set_property(TARGET vrpn PROPERTY FOLDER "External/SGCT") - set_property(TARGET zlibstatic PROPERTY FOLDER "External/SGCT") - - if (UNIX AND (NOT APPLE)) - target_link_libraries(libOpenSpace Xcursor Xinerama X11) - endif () - - # Spice - add_subdirectory(${OPENSPACE_EXT_DIR}/spice) - target_link_libraries(libOpenSpace Spice) - get_property(SPICE_INCLUDE_DIR TARGET Spice PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - target_include_directories(libOpenSpace PUBLIC ${SPICE_INCLUDE_DIR}) - set_property(TARGET Spice PROPERTY FOLDER "External") - - # Curl - if (WIN32) - set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl") - set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl" PARENT_SCOPE) - target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_ROOT_DIR}/include) - target_link_libraries(libOpenSpace ${CURL_ROOT_DIR}/lib/libcurl_imp.lib) - target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED" "CURL_STATICLIB") - else () - find_package(CURL) - if (CURL_FOUND) - target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_INCLUDE_DIRS}) - target_link_libraries(libOpenSpace ${CURL_LIBRARIES}) - target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED") - endif () - endif() - - # Qt - # Unfortunately, we have to set this value manually; sigh - # In the future, if the Qt version is updated, just add to this variable ---abock - if (APPLE) - set(CMAKE_PREFIX_PATH - "~/Qt/5.6/clang_64/lib/cmake" - "~/Qt/5.7/clang_64/lib/cmake" - PARENT_SCOPE - ) - endif () -endfunction () - - - -function (handle_applications) - set(applications "") - set(applications_link_to_openspace "") - - file(GLOB appDirs RELATIVE ${OPENSPACE_APPS_DIR} ${OPENSPACE_APPS_DIR}/*) - list(REMOVE_ITEM appDirs ".DS_Store") # Removing the .DS_Store present on Mac - - set(DEFAULT_APPLICATIONS - "OpenSpace" - "Launcher" - ) - mark_as_advanced(DEFAULT_APPLICATIONS) - - foreach (app ${appDirs}) - string(TOUPPER ${app} upper_app) - list (FIND DEFAULT_APPLICATIONS "${app}" _index) - if (${_index} GREATER -1) - # App is a default application - option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" ON) - else () - option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" OFF) - endif() - if (OPENSPACE_APPLICATION_${upper_app}) - unset(APPLICATION_NAME) - unset(APPLICATION_LINK_TO_OPENSPACE) - include(${OPENSPACE_APPS_DIR}/${app}/CMakeLists.txt) - set_compile_settings(${APPLICATION_NAME}) - - if (APPLICATION_LINK_TO_OPENSPACE) - get_property( - OPENSPACE_INCLUDE_DIR - TARGET libOpenSpace - PROPERTY INTERFACE_INCLUDE_DIRECTORIES - ) - target_include_directories(${APPLICATION_NAME} PUBLIC - "${OPENSPACE_BASE_DIR}" - ${OPENSPACE_INCLUDE_DIR} - ) - - get_property( - OPENSPACE_DEFINES - TARGET libOpenSpace - PROPERTY INTERFACE_COMPILE_DEFINITIONS - ) - target_compile_definitions(${APPLICATION_NAME} PUBLIC ${OPENSPACE_DEFINES}) - - target_link_libraries(${APPLICATION_NAME} Ghoul) - target_link_libraries(${APPLICATION_NAME} libOpenSpace) - - if (MSVC) - set_target_properties(${APPLICATION_NAME} PROPERTIES LINK_FLAGS - "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" - ) - endif () - - - if (WIN32) - ghl_copy_files( - ${APPLICATION_NAME} - "${CURL_ROOT_DIR}/lib/libcurl.dll" - "${CURL_ROOT_DIR}/lib/libeay32.dll" - "${CURL_ROOT_DIR}/lib/ssleay32.dll" - - ) - ghl_copy_shared_libraries(${APPLICATION_NAME} ${OPENSPACE_EXT_DIR}/ghoul) - endif () - endif () - - list(APPEND applications ${APPLICATION_NAME}) - list(APPEND applications_link_to_openspace ${APPLICATION_LINK_TO_OPENSPACE}) - unset(APPLICATION_NAME) - unset(APPLICATION_LINK_TO_OPENSPACE) - endif () - endforeach () - - - # option(OPENSPACE_APPLICATION_OPENSPACE "Main OpenSpace Application" ON) - # if (OPENSPACE_APPLICATION_OPENSPACE) - # include(${OPENSPACE_APPS_DIR}/OpenSpace/CMakeLists.txt) - # list(APPEND applications "OpenSpace") - # endif () - set(OPENSPACE_APPLICATIONS ${applications} PARENT_SCOPE) - set(OPENSPACE_APPLICATIONS_LINK_REQUEST ${applications_link_to_openspace} PARENT_SCOPE) - - message(STATUS "Applications:") - list(LENGTH applications len1) - math(EXPR len2 "${len1} - 1") - - foreach(val RANGE ${len2}) - list(GET applications ${val} val1) - list(GET applications_link_to_openspace ${val} val2) - message(STATUS "\t${val1} (Link: ${val2})") - endforeach() -endfunction() - - -function (handle_option_vld) - if (OPENSPACE_ENABLE_VLD) - target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_ENABLE_VLD") - target_link_libraries(libOpenSpace ${OPENSPACE_EXT_DIR}/vld/lib/vld.lib) - target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_EXT_DIR}/vld) - - foreach (app ${OPENSPACE_APPLCATIONS}) - ghl_copy_files(${app} "${OPENSPACE_EXT_DIR}/vld/bin/vld_x64.dll") - endforeach () - endif () -endfunction () - - - -function (handle_option_tests) - if (OPENSPACE_HAVE_TESTS) - if (NOT TARGET gtest) - set(BUILD_GTEST ON CACHE BOOL "") - set(BUILD_GMOCK OFF CACHE BOOL "") - set(gtest_force_shared_crt ON CACHE BOOL "") - # set(BUILD_GMOCK OFF CACHE BOOL "") - # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) - # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) - # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) - add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) - # add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/gtest) - set_property(TARGET gtest PROPERTY FOLDER "External") - set_property(TARGET gtest_main PROPERTY FOLDER "External") - endif () - - file(GLOB_RECURSE OPENSPACE_TEST_FILES ${OPENSPACE_BASE_DIR}/tests/*.inl) - - add_executable(OpenSpaceTest ${OPENSPACE_BASE_DIR}/tests/main.cpp ${OPENSPACE_TEST_FILES}) - target_include_directories(OpenSpaceTest PUBLIC - "${OPENSPACE_BASE_DIR}/include" - "${OPENSPACE_BASE_DIR}/tests" - "${OPENSPACE_EXT_DIR}/ghoul/ext/googletest/googletest/include" - ) - target_compile_definitions(OpenSpaceTest PUBLIC - "GHL_THROW_ON_ASSERT" - "GTEST_HAS_TR1_TUPLE=0" - ) - target_link_libraries(OpenSpaceTest gtest libOpenSpace) - - if (MSVC) - set_target_properties(OpenSpaceTest PROPERTIES LINK_FLAGS - "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" - ) - endif () - set_property(TARGET OpenSpaceTest PROPERTY FOLDER "Unit Tests") - set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD 14) - set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD_REQUIRED On) - endif (OPENSPACE_HAVE_TESTS) - if (TARGET GhoulTest) - if (NOT TARGET gtest) - set(BUILD_GTEST ON CACHE BOOL "") - set(BUILD_GMOCK OFF CACHE BOOL "") - set(gtest_force_shared_crt ON CACHE BOOL "") - # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) - # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) - # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) - add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) - endif () - - set_property(TARGET gtest PROPERTY FOLDER "External") - set_property(TARGET GhoulTest PROPERTY FOLDER "Unit Tests") - endif () -endfunction () - - - -function (handle_internal_modules) -# Get all modules in the correct order based on their dependencies - file(GLOB moduleDirs RELATIVE ${OPENSPACE_MODULE_DIR} ${OPENSPACE_MODULE_DIR}/*) - set(sortedModules ${moduleDirs}) - foreach (dir ${moduleDirs}) - if (IS_DIRECTORY ${OPENSPACE_MODULE_DIR}/${dir}) - set(defaultModule OFF) - if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") - unset(OPENSPACE_DEPENDENCIES) - unset(EXTERNAL_LIBRAY) - unset(DEFAULT_MODULE) - include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) - - if (DEFINED DEFAULT_MODULE) - set(defaultModule ${DEFAULT_MODULE}) - endif () - if (OPENSPACE_DEPENDENCIES) - foreach (dependency ${OPENSPACE_DEPENDENCIES}) - create_library_name(${dependency} library) - if (TARGET ${library}) - # already registered - list(REMOVE_ITEM OPENSPACE_DEPENDENCIES ${dependency}) - endif () - endforeach () - - list(APPEND OPENSPACE_DEPENDENCIES ${dir}) - list(FIND sortedModules ${dir} dir_index) - # if (NOT dir STREQUAL "base") - # list(INSERT OPENSPACE_DEPENDENCIES 0 "base") - # endif () - list(INSERT sortedModules ${dir_index} ${OPENSPACE_DEPENDENCIES}) - list(REMOVE_DUPLICATES sortedModules) - endif () - endif () - create_option_name(${dir} optionName) - option(${optionName} "Build ${dir} Module" ${defaultModule}) - # create_library_name(${module} ${library}) - else () - list(REMOVE_ITEM sortedModules ${dir}) - endif () - endforeach () - - # Automatically set dependent modules to ON - set(dir_list ${sortedModules}) - set(dll_list "") - list(REVERSE dir_list) - foreach (dir ${dir_list}) - create_option_name(${dir} optionName) - if (${optionName}) - if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") - unset(OPENSPACE_DEPENDENCIES) - unset(EXTERNAL_LIBRAY) - unset(DEFAULT_MODULE) - include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) - - if (OPENSPACE_DEPENDENCIES) - foreach (dependency ${OPENSPACE_DEPENDENCIES}) - create_option_name(${dependency} dependencyOptionName) - if (NOT ${dependencyOptionName}) - set(${dependencyOptionName} ON CACHE BOOL "ff" FORCE) - message(STATUS "${dependencyOptionName} was set to build, due to dependency towards ${optionName}") - endif () - endforeach () - endif () - endif () - endif () - endforeach () - - set(MODULE_HEADERS "") - set(MODULE_CLASSES "") - - message(STATUS "Included modules:") - foreach (module ${sortedModules}) - create_option_name(${module} optionName) - if (${optionName}) - message(STATUS "\t${module}") - endif () - endforeach () - - # Add subdirectories in the correct order - foreach (module ${sortedModules}) - create_option_name(${module} optionName) - if (${optionName}) - create_library_name(${module} libraryName) - add_subdirectory(${OPENSPACE_MODULE_DIR}/${module}) - - list(LENGTH OPENSPACE_APPLICATIONS len1) - math(EXPR len2 "${len1} - 1") - - foreach(val RANGE ${len2}) - list(GET OPENSPACE_APPLICATIONS ${val} val1) - list(GET OPENSPACE_APPLICATIONS_LINK_REQUEST ${val} val2) - if (${val2}) - target_link_libraries(${app} ${libraryName}) - endif () - endforeach() - - # Only link libOpenSpace against the library if it has been set STATIC - get_target_property(libType ${libraryName} TYPE) - if (NOT ${libType} STREQUAL "SHARED_LIBRARY") - target_link_libraries(libOpenSpace ${libraryName}) - endif() - - create_define_name(${module} defineName) - target_compile_definitions(libOpenSpace PUBLIC "${defineName}") - - # Create registration file - string(TOUPPER ${module} module_upper) - string(TOLOWER ${module} module_lower) - unset(MODULE_NAME) - unset(MODULE_PATH) - include(${CMAKE_BINARY_DIR}/modules/${module_lower}/modulename.cmake) - - list(APPEND MODULE_HEADERS - #"#ifdef REGISTRATION_OPENSPACE${module_upper}MODULE\n" - "#include <${MODULE_PATH}>\n" - #"#endif\n\n" - ) - list(APPEND MODULE_CLASSES " new ${MODULE_NAME},\n") - - if (EXTERNAL_LIBRARY) - foreach (library ${EXTERNAL_LIBRARY}) - get_filename_component(lib ${library} ABSOLUTE) - list(APPEND dll_list ${lib}) - endforeach() - endif () - endif () - endforeach () - - if (NOT "${MODULE_HEADERS}" STREQUAL "") - string(REPLACE ";" "" MODULE_HEADERS ${MODULE_HEADERS}) - endif () - - if (NOT "${MODULE_CLASSES}" STREQUAL "") - string(REPLACE ";" "" MODULE_CLASSES ${MODULE_CLASSES}) - endif () - - configure_file( - ${OPENSPACE_CMAKE_EXT_DIR}/module_registration.template - ${CMAKE_BINARY_DIR}/_generated/include/openspace/moduleregistration.h - ) - - list(REMOVE_DUPLICATES dll_list) - - if (WIN32) - foreach (application ${OPENSPACE_APPLICATIONS}) - foreach (dll ${dll_list}) - ghl_copy_files(${application} ${dll}) - endforeach () - endforeach () - endif () -endfunction () - - - -function (copy_dynamic_libraries) - if (WIN32) - ghl_copy_files(OpenSpace "${CURL_ROOT_DIR}/lib/libcurl.dll") - - # Copy DLLs needed by Ghoul into the executable directory - ghl_copy_shared_libraries(OpenSpace ${OPENSPACE_EXT_DIR}/ghoul) - - if (TARGET OpenSpaceTest) - ghl_copy_shared_libraries(OpenSpaceTest ${OPENSPACE_EXT_DIR}/ghoul) - endif () - endif () -endfunction () +######################################################################################### +# # +# OpenSpace # +# # +# Copyright (c) 2014-2017 # +# # +# Permission is hereby granted, free of charge, to any person obtaining a copy of this # +# software and associated documentation files (the "Software"), to deal in the Software # +# without restriction, including without limitation the rights to use, copy, modify, # +# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # +# permit persons to whom the Software is furnished to do so, subject to the following # +# conditions: # +# # +# The above copyright notice and this permission notice shall be included in all copies # +# or substantial portions of the Software. # +# # +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE # +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # +######################################################################################### + +function (test_compiler_compatibility) + if (MSVC) + if (MSVC_VERSION LESS 1900) + message(FATAL_ERROR "OpenSpace requires at least Visual Studio 2015") + endif () + endif () +endfunction () + + + +macro (cleanup_project) + # Remove MinSizeRel build option + set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE TYPE INTERNAL FORCE) + mark_as_advanced(CMAKE_CONFIGURATION_TYPES) + mark_as_advanced(CMAKE_INSTALL_PREFIX) + + set_property(GLOBAL PROPERTY USE_FOLDERS On) + set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER CMake) +endmacro () + + +macro (set_build_output_directories) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OPENSPACE_CMAKE_EXT_DIR}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/lib) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin/openspace) +endmacro () + + + +function (create_openspace_target) + add_library(libOpenSpace STATIC ${OPENSPACE_HEADER} ${OPENSPACE_SOURCE}) + target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}/include) + target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_BASE_DIR}) + target_include_directories(libOpenSpace PUBLIC ${CMAKE_BINARY_DIR}/_generated/include) + + configure_file( + ${OPENSPACE_CMAKE_EXT_DIR}/openspace_header.template + ${CMAKE_BINARY_DIR}/_generated/include/openspace/openspace.h + @ONLY IMMEDIATE + ) + + set_compile_settings(libOpenSpace) +endfunction () + + + +function (set_compile_settings project) + set_property(TARGET ${project} PROPERTY CXX_STANDARD 17) + set_property(TARGET ${project} PROPERTY CXX_STANDARD_REQUIRED On) + + if (MSVC) + target_compile_options(${project} PRIVATE + "/ZI" # Edit and continue support + "/MP" # Multi-threading support + "/W4" # Highest warning level + "/w44062" # enumerator 'identifier' in a switch of enum 'enumeration' is not handled + "/wd4127" # conditional expression is constant + "/wd4201" # nonstandard extension used : nameless struct/union + "/w44255" # 'function': no function prototype given: converting '()' to '(void)' + "/w44263" # 'function': member function does not override any base class virtual member function + "/w44264" # 'virtual_function': no override available for virtual member function from base 'class'; function is hidden + "/w44265" # 'class': class has virtual functions, but destructor is not virtual + "/w44266" # 'function': no override available for virtual member function from base 'type'; function is hidden + "/w44289" # nonstandard extension used : 'var' : loop control variable declared in the for-loop is used outside the for-loop scope + "/w44296" # 'operator': expression is always false + "/w44311" # 'variable' : pointer truncation from 'type' to 'type' + "/w44339" # 'type' : use of undefined type detected in CLR meta-data - use of this type may lead to a runtime exception + "/w44342" # behavior change: 'function' called, but a member operator was called in previous versions + "/w44350" # behavior change: 'member1' called instead of 'member2' + "/w44431" # missing type specifier - int assumed. Note: C no longer supports default-int + "/w44471" # a forward declaration of an unscoped enumeration must have an underlying type (int assumed) + "/w44545" # expression before comma evaluates to a function which is missing an argument list + "/w44546" # function call before comma missing argument list + "/w44547" # 'operator': operator before comma has no effect; expected operator with side-effect + "/w44548" # expression before comma has no effect; expected expression with side-effect + "/w44549" # 'operator': operator before comma has no effect; did you intend 'operator'? + "/w44555" # expression has no effect; expected expression with side-effect + "/w44574" # 'identifier' is defined to be '0': did you mean to use '#if identifier'? + "/w44608" # 'symbol1' has already been initialized by another union member in the initializer list, 'symbol2' + "/w44619" # #pragma warning: there is no warning number 'number' + "/w44628" # digraphs not supported with -Ze. Character sequence 'digraph' not interpreted as alternate token for 'char' + "/w44640" # 'instance': construction of local static object is not thread-safe + "/w44905" # wide string literal cast to 'LPSTR' + "/w44906" # string literal cast to 'LPWSTR' + "/w44946" # reinterpret_cast used between related classes: 'class1' and 'class2' + "/w44986" # 'symbol': exception specification does not match previous declaration + "/w44988" # 'symbol': variable declared outside class/function scope + # "/std:c++latest" # Boost as of 1.64 still uses unary_function + "/permissive-" + "/Zc:strictStrings-" # Windows header don't adhere to this + ) + if (OPENSPACE_WARNINGS_AS_ERRORS) + target_compile_options(${project} PRIVATE "/WX") + endif () + elseif (APPLE) + target_compile_definitions(${project} PRIVATE "__APPLE__") + + if (OPENSPACE_WARNINGS_AS_ERRORS) + target_compile_options(${project} PRIVATE "-Werror") + endif () + + target_compile_options(${project} PRIVATE "-stdlib=libc++") + + target_include_directories(${project} PUBLIC "/Developer/Headers/FlatCarbon") + find_library(COREFOUNDATION_LIBRARY CoreFoundation) + find_library(CARBON_LIBRARY Carbon) + find_library(COCOA_LIBRARY Carbon) + find_library(APP_SERVICES_LIBRARY ApplicationServices) + mark_as_advanced(CARBON_LIBRARY COCOA_LIBRARY APP_SERVICES_LIBRARY) + target_link_libraries(${project} + ${CARBON_LIBRARY} + ${COREFOUNDATION_LIBRARY} + ${COCOA_LIBRARY} + ${APP_SERVICES_LIBRARY} + ) + elseif (UNIX) + target_compile_options(${project} PRIVATE "-ggdb" "-Wall" "-Wno-long-long" "-pedantic" "-Wextra") + + if (OPENSPACE_WARNINGS_AS_ERRORS) + target_compile_options(${project} PRIVATE "-Werror") + endif () + endif () +endfunction () + + + +function (add_external_dependencies) + # Ghoul + add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul) + target_link_libraries(libOpenSpace Ghoul) + get_property(GHOUL_INCLUDE_DIR TARGET Ghoul PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + target_include_directories(libOpenSpace PUBLIC ${GHOUL_INCLUDE_DIR}) + get_property(GHOUL_DEFINITIONS TARGET Ghoul PROPERTY INTERFACE_COMPILE_DEFINITIONS) + target_compile_definitions(libOpenSpace PUBLIC ${GHOUL_DEFINITIONS}) + set_property(TARGET Lua PROPERTY FOLDER "External") + set_property(TARGET lz4 PROPERTY FOLDER "External") + + # SGCT + set(SGCT_TEXT OFF CACHE BOOL "" FORCE) + set(SGCT_BUILD_CSHARP_PROJECTS OFF CACHE BOOL "" FORCE) + set(SGCT_LIGHT_ONLY ON CACHE BOOL "" FORCE) + set(SGCT_CUSTOMOUTPUTDIRS OFF CACHE BOOL "" FORCE) + + add_subdirectory(${OPENSPACE_EXT_DIR}/sgct) + target_include_directories(libOpenSpace SYSTEM PUBLIC ${OPENSPACE_EXT_DIR}/sgct/include) + target_link_libraries( + libOpenSpace + # sgct + sgct_light glew glfw png16_static quat tinyxml2static turbojpeg-static + vrpn + ${GLFW_LIBRARIES} + ) + + set_property(TARGET sgct_light PROPERTY FOLDER "External") + set_property(TARGET glew PROPERTY FOLDER "External/SGCT") + set_property(TARGET glfw PROPERTY FOLDER "External/SGCT") + set_property(TARGET png16_static PROPERTY FOLDER "External/SGCT") + set_property(TARGET quat PROPERTY FOLDER "External/SGCT") + set_property(TARGET simd PROPERTY FOLDER "External/SGCT") + set_property(TARGET tinyxml2static PROPERTY FOLDER "External/SGCT") + set_property(TARGET turbojpeg-static PROPERTY FOLDER "External/SGCT") + set_property(TARGET vrpn PROPERTY FOLDER "External/SGCT") + set_property(TARGET zlibstatic PROPERTY FOLDER "External/SGCT") + + if (UNIX AND (NOT APPLE)) + target_link_libraries(libOpenSpace Xcursor Xinerama X11) + endif () + + # Spice + add_subdirectory(${OPENSPACE_EXT_DIR}/spice) + target_link_libraries(libOpenSpace Spice) + get_property(SPICE_INCLUDE_DIR TARGET Spice PROPERTY INTERFACE_INCLUDE_DIRECTORIES) + target_include_directories(libOpenSpace PUBLIC ${SPICE_INCLUDE_DIR}) + set_property(TARGET Spice PROPERTY FOLDER "External") + + # Curl + if (WIN32) + set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl") + set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl" PARENT_SCOPE) + target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_ROOT_DIR}/include) + target_link_libraries(libOpenSpace ${CURL_ROOT_DIR}/lib/libcurl_imp.lib) + target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED" "CURL_STATICLIB") + else () + find_package(CURL) + if (CURL_FOUND) + target_include_directories(libOpenSpace SYSTEM PUBLIC ${CURL_INCLUDE_DIRS}) + target_link_libraries(libOpenSpace ${CURL_LIBRARIES}) + target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_CURL_ENABLED") + endif () + endif() + + # Qt + # Unfortunately, we have to set this value manually; sigh + # In the future, if the Qt version is updated, just add to this variable ---abock + if (APPLE) + set(CMAKE_PREFIX_PATH + "~/Qt/5.6/clang_64/lib/cmake" + "~/Qt/5.7/clang_64/lib/cmake" + PARENT_SCOPE + ) + endif () +endfunction () + + + +function (handle_applications) + set(applications "") + set(applications_link_to_openspace "") + + file(GLOB appDirs RELATIVE ${OPENSPACE_APPS_DIR} ${OPENSPACE_APPS_DIR}/*) + list(REMOVE_ITEM appDirs ".DS_Store") # Removing the .DS_Store present on Mac + + set(DEFAULT_APPLICATIONS + "OpenSpace" + "Launcher" + ) + mark_as_advanced(DEFAULT_APPLICATIONS) + + foreach (app ${appDirs}) + string(TOUPPER ${app} upper_app) + list (FIND DEFAULT_APPLICATIONS "${app}" _index) + if (${_index} GREATER -1) + # App is a default application + option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" ON) + else () + option(OPENSPACE_APPLICATION_${upper_app} "${app} Application" OFF) + endif() + if (OPENSPACE_APPLICATION_${upper_app}) + unset(APPLICATION_NAME) + unset(APPLICATION_LINK_TO_OPENSPACE) + include(${OPENSPACE_APPS_DIR}/${app}/CMakeLists.txt) + set_compile_settings(${APPLICATION_NAME}) + + if (APPLICATION_LINK_TO_OPENSPACE) + get_property( + OPENSPACE_INCLUDE_DIR + TARGET libOpenSpace + PROPERTY INTERFACE_INCLUDE_DIRECTORIES + ) + target_include_directories(${APPLICATION_NAME} PUBLIC + "${OPENSPACE_BASE_DIR}" + ${OPENSPACE_INCLUDE_DIR} + ) + + get_property( + OPENSPACE_DEFINES + TARGET libOpenSpace + PROPERTY INTERFACE_COMPILE_DEFINITIONS + ) + target_compile_definitions(${APPLICATION_NAME} PUBLIC ${OPENSPACE_DEFINES}) + + target_link_libraries(${APPLICATION_NAME} Ghoul) + target_link_libraries(${APPLICATION_NAME} libOpenSpace) + + if (MSVC) + set_target_properties(${APPLICATION_NAME} PROPERTIES LINK_FLAGS + "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" + ) + endif () + + + if (WIN32) + ghl_copy_files( + ${APPLICATION_NAME} + "${CURL_ROOT_DIR}/lib/libcurl.dll" + "${CURL_ROOT_DIR}/lib/libeay32.dll" + "${CURL_ROOT_DIR}/lib/ssleay32.dll" + + ) + ghl_copy_shared_libraries(${APPLICATION_NAME} ${OPENSPACE_EXT_DIR}/ghoul) + endif () + endif () + + list(APPEND applications ${APPLICATION_NAME}) + list(APPEND applications_link_to_openspace ${APPLICATION_LINK_TO_OPENSPACE}) + unset(APPLICATION_NAME) + unset(APPLICATION_LINK_TO_OPENSPACE) + endif () + endforeach () + + + # option(OPENSPACE_APPLICATION_OPENSPACE "Main OpenSpace Application" ON) + # if (OPENSPACE_APPLICATION_OPENSPACE) + # include(${OPENSPACE_APPS_DIR}/OpenSpace/CMakeLists.txt) + # list(APPEND applications "OpenSpace") + # endif () + set(OPENSPACE_APPLICATIONS ${applications} PARENT_SCOPE) + set(OPENSPACE_APPLICATIONS_LINK_REQUEST ${applications_link_to_openspace} PARENT_SCOPE) + + message(STATUS "Applications:") + list(LENGTH applications len1) + math(EXPR len2 "${len1} - 1") + + foreach(val RANGE ${len2}) + list(GET applications ${val} val1) + list(GET applications_link_to_openspace ${val} val2) + message(STATUS "\t${val1} (Link: ${val2})") + endforeach() +endfunction() + + +function (handle_option_vld) + if (OPENSPACE_ENABLE_VLD) + target_compile_definitions(libOpenSpace PUBLIC "OPENSPACE_ENABLE_VLD") + target_link_libraries(libOpenSpace ${OPENSPACE_EXT_DIR}/vld/lib/vld.lib) + target_include_directories(libOpenSpace PUBLIC ${OPENSPACE_EXT_DIR}/vld) + + foreach (app ${OPENSPACE_APPLCATIONS}) + ghl_copy_files(${app} "${OPENSPACE_EXT_DIR}/vld/bin/vld_x64.dll") + endforeach () + endif () +endfunction () + + + +function (handle_option_tests) + if (OPENSPACE_HAVE_TESTS) + if (NOT TARGET gtest) + set(BUILD_GTEST ON CACHE BOOL "") + set(BUILD_GMOCK OFF CACHE BOOL "") + set(gtest_force_shared_crt ON CACHE BOOL "") + # set(BUILD_GMOCK OFF CACHE BOOL "") + # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) + # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) + # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) + add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) + # add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/gtest) + set_property(TARGET gtest PROPERTY FOLDER "External") + set_property(TARGET gtest_main PROPERTY FOLDER "External") + endif () + + file(GLOB_RECURSE OPENSPACE_TEST_FILES ${OPENSPACE_BASE_DIR}/tests/*.inl) + + add_executable(OpenSpaceTest ${OPENSPACE_BASE_DIR}/tests/main.cpp ${OPENSPACE_TEST_FILES}) + target_include_directories(OpenSpaceTest PUBLIC + "${OPENSPACE_BASE_DIR}/include" + "${OPENSPACE_BASE_DIR}/tests" + "${OPENSPACE_EXT_DIR}/ghoul/ext/googletest/googletest/include" + ) + target_compile_definitions(OpenSpaceTest PUBLIC + "GHL_THROW_ON_ASSERT" + "GTEST_HAS_TR1_TUPLE=0" + ) + target_link_libraries(OpenSpaceTest gtest libOpenSpace) + + if (MSVC) + set_target_properties(OpenSpaceTest PROPERTIES LINK_FLAGS + "/NODEFAULTLIB:LIBCMTD.lib /NODEFAULTLIB:LIBCMT.lib" + ) + endif () + set_property(TARGET OpenSpaceTest PROPERTY FOLDER "Unit Tests") + set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD 14) + set_property(TARGET OpenSpaceTest PROPERTY CXX_STANDARD_REQUIRED On) + endif (OPENSPACE_HAVE_TESTS) + if (TARGET GhoulTest) + if (NOT TARGET gtest) + set(BUILD_GTEST ON CACHE BOOL "") + set(BUILD_GMOCK OFF CACHE BOOL "") + set(gtest_force_shared_crt ON CACHE BOOL "") + # option(BUILD_GTEST "Builds the googletest subproject" CACHE ON) + # option(BUILD_GMOCK "Builds the googlemock subproject" CACHE OFF) + # option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." CACHE ON) + add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul/ext/googletest) + endif () + + set_property(TARGET gtest PROPERTY FOLDER "External") + set_property(TARGET GhoulTest PROPERTY FOLDER "Unit Tests") + endif () +endfunction () + + + +function (handle_internal_modules) +# Get all modules in the correct order based on their dependencies + file(GLOB moduleDirs RELATIVE ${OPENSPACE_MODULE_DIR} ${OPENSPACE_MODULE_DIR}/*) + set(sortedModules ${moduleDirs}) + foreach (dir ${moduleDirs}) + if (IS_DIRECTORY ${OPENSPACE_MODULE_DIR}/${dir}) + set(defaultModule OFF) + if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") + unset(OPENSPACE_DEPENDENCIES) + unset(EXTERNAL_LIBRAY) + unset(DEFAULT_MODULE) + include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) + + if (DEFINED DEFAULT_MODULE) + set(defaultModule ${DEFAULT_MODULE}) + endif () + if (OPENSPACE_DEPENDENCIES) + foreach (dependency ${OPENSPACE_DEPENDENCIES}) + create_library_name(${dependency} library) + if (TARGET ${library}) + # already registered + list(REMOVE_ITEM OPENSPACE_DEPENDENCIES ${dependency}) + endif () + endforeach () + + list(APPEND OPENSPACE_DEPENDENCIES ${dir}) + list(FIND sortedModules ${dir} dir_index) + # if (NOT dir STREQUAL "base") + # list(INSERT OPENSPACE_DEPENDENCIES 0 "base") + # endif () + list(INSERT sortedModules ${dir_index} ${OPENSPACE_DEPENDENCIES}) + list(REMOVE_DUPLICATES sortedModules) + endif () + endif () + create_option_name(${dir} optionName) + option(${optionName} "Build ${dir} Module" ${defaultModule}) + # create_library_name(${module} ${library}) + else () + list(REMOVE_ITEM sortedModules ${dir}) + endif () + endforeach () + + # Automatically set dependent modules to ON + set(dir_list ${sortedModules}) + set(dll_list "") + list(REVERSE dir_list) + foreach (dir ${dir_list}) + create_option_name(${dir} optionName) + if (${optionName}) + if (EXISTS "${OPENSPACE_MODULE_DIR}/${dir}/include.cmake") + unset(OPENSPACE_DEPENDENCIES) + unset(EXTERNAL_LIBRAY) + unset(DEFAULT_MODULE) + include(${OPENSPACE_MODULE_DIR}/${dir}/include.cmake) + + if (OPENSPACE_DEPENDENCIES) + foreach (dependency ${OPENSPACE_DEPENDENCIES}) + create_option_name(${dependency} dependencyOptionName) + if (NOT ${dependencyOptionName}) + set(${dependencyOptionName} ON CACHE BOOL "ff" FORCE) + message(STATUS "${dependencyOptionName} was set to build, due to dependency towards ${optionName}") + endif () + endforeach () + endif () + endif () + endif () + endforeach () + + set(MODULE_HEADERS "") + set(MODULE_CLASSES "") + + message(STATUS "Included modules:") + foreach (module ${sortedModules}) + create_option_name(${module} optionName) + if (${optionName}) + message(STATUS "\t${module}") + endif () + endforeach () + + # Add subdirectories in the correct order + foreach (module ${sortedModules}) + create_option_name(${module} optionName) + if (${optionName}) + create_library_name(${module} libraryName) + add_subdirectory(${OPENSPACE_MODULE_DIR}/${module}) + + list(LENGTH OPENSPACE_APPLICATIONS len1) + math(EXPR len2 "${len1} - 1") + + foreach(val RANGE ${len2}) + list(GET OPENSPACE_APPLICATIONS ${val} val1) + list(GET OPENSPACE_APPLICATIONS_LINK_REQUEST ${val} val2) + if (${val2}) + target_link_libraries(${app} ${libraryName}) + endif () + endforeach() + + # Only link libOpenSpace against the library if it has been set STATIC + get_target_property(libType ${libraryName} TYPE) + if (NOT ${libType} STREQUAL "SHARED_LIBRARY") + target_link_libraries(libOpenSpace ${libraryName}) + endif() + + create_define_name(${module} defineName) + target_compile_definitions(libOpenSpace PUBLIC "${defineName}") + + # Create registration file + string(TOUPPER ${module} module_upper) + string(TOLOWER ${module} module_lower) + unset(MODULE_NAME) + unset(MODULE_PATH) + include(${CMAKE_BINARY_DIR}/modules/${module_lower}/modulename.cmake) + + list(APPEND MODULE_HEADERS + #"#ifdef REGISTRATION_OPENSPACE${module_upper}MODULE\n" + "#include <${MODULE_PATH}>\n" + #"#endif\n\n" + ) + list(APPEND MODULE_CLASSES " new ${MODULE_NAME},\n") + + if (EXTERNAL_LIBRARY) + foreach (library ${EXTERNAL_LIBRARY}) + get_filename_component(lib ${library} ABSOLUTE) + list(APPEND dll_list ${lib}) + endforeach() + endif () + endif () + endforeach () + + if (NOT "${MODULE_HEADERS}" STREQUAL "") + string(REPLACE ";" "" MODULE_HEADERS ${MODULE_HEADERS}) + endif () + + if (NOT "${MODULE_CLASSES}" STREQUAL "") + string(REPLACE ";" "" MODULE_CLASSES ${MODULE_CLASSES}) + endif () + + configure_file( + ${OPENSPACE_CMAKE_EXT_DIR}/module_registration.template + ${CMAKE_BINARY_DIR}/_generated/include/openspace/moduleregistration.h + ) + + list(REMOVE_DUPLICATES dll_list) + + if (WIN32) + foreach (application ${OPENSPACE_APPLICATIONS}) + foreach (dll ${dll_list}) + ghl_copy_files(${application} ${dll}) + endforeach () + endforeach () + endif () +endfunction () + + + +function (copy_dynamic_libraries) + if (WIN32) + ghl_copy_files(OpenSpace "${CURL_ROOT_DIR}/lib/libcurl.dll") + + # Copy DLLs needed by Ghoul into the executable directory + ghl_copy_shared_libraries(OpenSpace ${OPENSPACE_EXT_DIR}/ghoul) + + if (TARGET OpenSpaceTest) + ghl_copy_shared_libraries(OpenSpaceTest ${OPENSPACE_EXT_DIR}/ghoul) + endif () + endif () +endfunction () From c26fe4b2792397eb4286a49b941eeb8212b49840 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 8 Jul 2017 16:06:45 -0400 Subject: [PATCH 144/192] Move SGCT config files into main config folder and remove unused transferfunctions --- config/{sgct => }/openvr_htcVive.xml | 46 ++--- config/{sgct => }/openvr_oculusRiftCv1.xml | 46 ++--- config/{sgct => }/single.xml | 48 +++--- config/{sgct => }/single_fisheye.xml | 74 ++++---- config/{sgct => }/single_gui.xml | 74 ++++---- config/{sgct => }/single_two_win.xml | 62 +++---- config/transferfunctions/blue.txt | 8 - config/transferfunctions/fire.txt | 15 -- config/transferfunctions/ml.txt | 8 - config/transferfunctions/plain.txt | 5 - config/transferfunctions/test.txt | 14 -- config/{sgct => }/two_nodes.xml | 70 ++++---- ext/ghoul | 2 +- openspace.cfg | 191 ++++++++++----------- 14 files changed, 306 insertions(+), 357 deletions(-) rename config/{sgct => }/openvr_htcVive.xml (97%) rename config/{sgct => }/openvr_oculusRiftCv1.xml (97%) rename config/{sgct => }/single.xml (97%) rename config/{sgct => }/single_fisheye.xml (97%) rename config/{sgct => }/single_gui.xml (97%) rename config/{sgct => }/single_two_win.xml (97%) delete mode 100644 config/transferfunctions/blue.txt delete mode 100644 config/transferfunctions/fire.txt delete mode 100644 config/transferfunctions/ml.txt delete mode 100644 config/transferfunctions/plain.txt delete mode 100644 config/transferfunctions/test.txt rename config/{sgct => }/two_nodes.xml (97%) diff --git a/config/sgct/openvr_htcVive.xml b/config/openvr_htcVive.xml similarity index 97% rename from config/sgct/openvr_htcVive.xml rename to config/openvr_htcVive.xml index e663b11521..b239d0283b 100644 --- a/config/sgct/openvr_htcVive.xml +++ b/config/openvr_htcVive.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/sgct/openvr_oculusRiftCv1.xml b/config/openvr_oculusRiftCv1.xml similarity index 97% rename from config/sgct/openvr_oculusRiftCv1.xml rename to config/openvr_oculusRiftCv1.xml index e264dd3788..917991d559 100644 --- a/config/sgct/openvr_oculusRiftCv1.xml +++ b/config/openvr_oculusRiftCv1.xml @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/sgct/single.xml b/config/single.xml similarity index 97% rename from config/sgct/single.xml rename to config/single.xml index 6f8f58b23b..ed397f50fe 100644 --- a/config/sgct/single.xml +++ b/config/single.xml @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/sgct/single_fisheye.xml b/config/single_fisheye.xml similarity index 97% rename from config/sgct/single_fisheye.xml rename to config/single_fisheye.xml index b9bc7415dd..da491287e5 100644 --- a/config/sgct/single_fisheye.xml +++ b/config/single_fisheye.xml @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/sgct/single_gui.xml b/config/single_gui.xml similarity index 97% rename from config/sgct/single_gui.xml rename to config/single_gui.xml index 129232a9ea..d17ab77c79 100644 --- a/config/sgct/single_gui.xml +++ b/config/single_gui.xml @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/sgct/single_two_win.xml b/config/single_two_win.xml similarity index 97% rename from config/sgct/single_two_win.xml rename to config/single_two_win.xml index 2f7f49efc6..3c20b3191e 100644 --- a/config/sgct/single_two_win.xml +++ b/config/single_two_win.xml @@ -1,32 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/transferfunctions/blue.txt b/config/transferfunctions/blue.txt deleted file mode 100644 index eb6b9b98d5..0000000000 --- a/config/transferfunctions/blue.txt +++ /dev/null @@ -1,8 +0,0 @@ -width 1024 -lower 0.0 -upper 0.7 -mappingkey 0.001 0 0 1 1 -mappingkey 0.01 2 2 0 2 -mappingkey 0.2 50 50 25 50 -mappingkey 0.35 100 100 100 100 -mappingkey 0.51 200 200 100 200 diff --git a/config/transferfunctions/fire.txt b/config/transferfunctions/fire.txt deleted file mode 100644 index 1e67f2dac9..0000000000 --- a/config/transferfunctions/fire.txt +++ /dev/null @@ -1,15 +0,0 @@ -width 1024 -lower 0.0 -upper 0.99 -mappingkey 0.0035 1 1 1 1 -mappingkey 0.0045 3 0 0 1 -mappingkey 0.0060 3 0 0 2 -mappingkey 0.0100 4 1 0 3 -mappingkey 0.0200 6 2 0 3 -mappingkey 0.0300 8 3 0 3 -mappingkey 0.0350 10 4 0 4 -mappingkey 0.0400 12 6 0 5 -mappingkey 0.0800 14 10 0 5 -mappingkey 0.1000 16 12 0 5 -mappingkey 0.2000 50 50 10 10 -mappingkey 0.2500 200 200 200 200 diff --git a/config/transferfunctions/ml.txt b/config/transferfunctions/ml.txt deleted file mode 100644 index f3e0ff894c..0000000000 --- a/config/transferfunctions/ml.txt +++ /dev/null @@ -1,8 +0,0 @@ -width 1024 -lower 0.0 -upper 1.0 -mappingkey 0.0 0 0 0 0 -mappingkey 0.45 5 0 0 5 -mappingkey 0.5 0 100 0 100 -mappingkey 0.55 0 0 5 5 -mappingkey 0.99 0 0 0 0 diff --git a/config/transferfunctions/plain.txt b/config/transferfunctions/plain.txt deleted file mode 100644 index 3fef1c1c21..0000000000 --- a/config/transferfunctions/plain.txt +++ /dev/null @@ -1,5 +0,0 @@ -width 1024 -lower 0.0 -upper 1.0 -mappingkey 0.1 20 20 20 10 -mappingkey 0.9 20 20 20 10 diff --git a/config/transferfunctions/test.txt b/config/transferfunctions/test.txt deleted file mode 100644 index 3e4abfbbcc..0000000000 --- a/config/transferfunctions/test.txt +++ /dev/null @@ -1,14 +0,0 @@ -width 1024 -lower 0.0 -upper 0.5 -mappingkey 0.0035 1 1 1 1 -mappingkey 0.0045 3 0 0 1 -mappingkey 0.0060 3 0 0 2 -mappingkey 0.0100 4 1 0 3 -mappingkey 0.0200 6 2 0 3 -mappingkey 0.0300 8 3 0 3 -mappingkey 0.0400 12 6 0 5 -mappingkey 0.0800 14 10 0 5 -mappingkey 0.1000 16 12 0 5 -mappingkey 0.2000 50 50 10 10 -mappingkey 0.2500 200 200 200 200 diff --git a/config/sgct/two_nodes.xml b/config/two_nodes.xml similarity index 97% rename from config/sgct/two_nodes.xml rename to config/two_nodes.xml index b4ae20f8c0..941fb90cb8 100644 --- a/config/sgct/two_nodes.xml +++ b/config/two_nodes.xml @@ -1,36 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ext/ghoul b/ext/ghoul index 5b75ba44ca..5244f74176 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 5b75ba44caec9ee798f7a3390dbdcb4870398886 +Subproject commit 5244f7417681128b60c34150f28c201ca6e6c024 diff --git a/openspace.cfg b/openspace.cfg index 79bb18dad3..526eaec369 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -1,96 +1,95 @@ --- The configuration has an implict --- require('scripts/configuration_helper.lua') --- which defines helper functions useful to customize the configuration - -return { - -- Determines which SGCT configuration file is loaded, that is, if there rendering - -- occurs in a single window, a fisheye projection, or a dome cluster system - - -- A regular 1280x720 window - SGCTConfig = sgct.config.single{}, - - -- A regular 1920x1080 window - -- SGCTConfig = sgct.config.single{1920, 1080}, - - -- A 1k fisheye rendering - -- SGCTConfig = sgct.config.fisheye{1024, 1024}, - - -- A 4k fisheye rendering in a 1024x1024 window - -- SGCTConfig = sgct.config.fisheye{1024, 1024, res={4096, 4096}, quality="2k", tilt=27}, - - -- Streaming OpenSpace via Spout to OBS - -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, - - - --SGCTConfig = "${SGCT}/openvr_oculusRiftCv1.xml", - --SGCTConfig = "${SGCT}/openvr_htcVive.xml", - - -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description - -- of all entities that will be visible during an instance of OpenSpace - Scene = "${SCENE}/default.scene", - -- Scene = "${SCENE}/globebrowsing.scene", - -- Scene = "${SCENE}/rosetta.scene", - -- Scene = "${SCENE}/dawn.scene", - -- Scene = "${SCENE}/newhorizons.scene", - -- Scene = "${SCENE}/osirisrex.scene", - - Task = "${TASKS}/default.task", - - Paths = { - SGCT = "${BASE_PATH}/config/sgct", - SCRIPTS = "${BASE_PATH}/scripts", - SHADERS = "${BASE_PATH}/shaders", - OPENSPACE_DATA = "${BASE_PATH}/data", - SCENE = "${OPENSPACE_DATA}/scene", - TASKS = "${OPENSPACE_DATA}/tasks", - SPICE = "${OPENSPACE_DATA}/spice", - MODULES = "${BASE_PATH}/modules", - TESTDIR = "${BASE_PATH}/tests", - CONFIG = "${BASE_PATH}/config", - CACHE = "${BASE_PATH}/cache", - FONTS = "${OPENSPACE_DATA}/fonts", - DOCUMENTATION = "${BASE_PATH}/documentation" - }, - Fonts = { - Mono = "${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf", - Light = "${FONTS}/Roboto/Roboto-Regular.ttf", - Console = "${FONTS}/Inconsolata/Inconsolata-Regular.ttf" - }, - Logging = { - -- LogLevel = "Trace", - LogLevel = "Debug", - ImmediateFlush = true, - Logs = { - { Type = "html", File = "${BASE_PATH}/log.html", Append = false } - }, - CapabilitiesVerbosity = "Full" - }, - Launcher = { - LogLevel = "None" - }, - LuaDocumentation = "${DOCUMENTATION}/LuaScripting.html", - PropertyDocumentation = "${DOCUMENTATION}/Properties.html", - ScriptLog = "${BASE_PATH}/ScriptLog.txt", - KeyboardShortcuts = "${DOCUMENTATION}/KeyboardMapping.html", - Documentation = "${DOCUMENTATION}/Documentation.html", - FactoryDocumentation = "${DOCUMENTATION}/FactoryDocumentation.html", - - ShutdownCountdown = 3, - -- OnScreenTextScaling = "framebuffer", - -- PerSceneCache = true, - -- DisableRenderingOnMaster = true, - -- DisableSceneOnMaster = true, - DownloadRequestURL = "http://data.openspaceproject.com/request.cgi", - RenderingMethod = "Framebuffer", - OpenGLDebugContext = { - Activate = true, - FilterIdentifier = { - { Type = "Other", Source = "API", Identifier = 131185 }, - { Type = "Performance", Source = "API", Identifier = 131186 }, --Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" - { Type = "Deprecated", Source = "API", Identifier = 7} -- API_ID_LINE_WIDTH deprecated behavior warning has been generated - }, --- FilterSeverity = { } - - } - --RenderingMethod = "ABuffer" -- alternative: "Framebuffer" -} +-- The configuration has an implict +-- require('scripts/configuration_helper.lua') +-- which defines helper functions useful to customize the configuration + +return { + -- Determines which SGCT configuration file is loaded, that is, if there rendering + -- occurs in a single window, a fisheye projection, or a dome cluster system + + -- A regular 1280x720 window + SGCTConfig = sgct.config.single{}, + + -- A regular 1920x1080 window + -- SGCTConfig = sgct.config.single{1920, 1080}, + + -- A 1k fisheye rendering + -- SGCTConfig = sgct.config.fisheye{1024, 1024}, + + -- A 4k fisheye rendering in a 1024x1024 window + -- SGCTConfig = sgct.config.fisheye{1024, 1024, res={4096, 4096}, quality="2k", tilt=27}, + + -- Streaming OpenSpace via Spout to OBS + -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, + + + --SGCTConfig = "${CONFIG}/openvr_oculusRiftCv1.xml", + --SGCTConfig = "${CONFIG}/openvr_htcVive.xml", + + -- Sets the scene that is to be loaded by OpenSpace. A scene file is a description + -- of all entities that will be visible during an instance of OpenSpace + Scene = "${SCENE}/default.scene", + -- Scene = "${SCENE}/globebrowsing.scene", + -- Scene = "${SCENE}/rosetta.scene", + -- Scene = "${SCENE}/dawn.scene", + -- Scene = "${SCENE}/newhorizons.scene", + -- Scene = "${SCENE}/osirisrex.scene", + + Task = "${TASKS}/default.task", + + Paths = { + SCRIPTS = "${BASE_PATH}/scripts", + SHADERS = "${BASE_PATH}/shaders", + OPENSPACE_DATA = "${BASE_PATH}/data", + SCENE = "${OPENSPACE_DATA}/scene", + TASKS = "${OPENSPACE_DATA}/tasks", + SPICE = "${OPENSPACE_DATA}/spice", + MODULES = "${BASE_PATH}/modules", + TESTDIR = "${BASE_PATH}/tests", + CONFIG = "${BASE_PATH}/config", + CACHE = "${BASE_PATH}/cache", + FONTS = "${OPENSPACE_DATA}/fonts", + DOCUMENTATION = "${BASE_PATH}/documentation" + }, + Fonts = { + Mono = "${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf", + Light = "${FONTS}/Roboto/Roboto-Regular.ttf", + Console = "${FONTS}/Inconsolata/Inconsolata-Regular.ttf" + }, + Logging = { + -- LogLevel = "Trace", + LogLevel = "Debug", + ImmediateFlush = true, + Logs = { + { Type = "html", File = "${BASE_PATH}/log.html", Append = false } + }, + CapabilitiesVerbosity = "Full" + }, + Launcher = { + LogLevel = "None" + }, + LuaDocumentation = "${DOCUMENTATION}/LuaScripting.html", + PropertyDocumentation = "${DOCUMENTATION}/Properties.html", + ScriptLog = "${BASE_PATH}/ScriptLog.txt", + KeyboardShortcuts = "${DOCUMENTATION}/KeyboardMapping.html", + Documentation = "${DOCUMENTATION}/Documentation.html", + FactoryDocumentation = "${DOCUMENTATION}/FactoryDocumentation.html", + + ShutdownCountdown = 3, + -- OnScreenTextScaling = "framebuffer", + -- PerSceneCache = true, + -- DisableRenderingOnMaster = true, + -- DisableSceneOnMaster = true, + DownloadRequestURL = "http://data.openspaceproject.com/request.cgi", + RenderingMethod = "Framebuffer", + OpenGLDebugContext = { + Activate = true, + FilterIdentifier = { + { Type = "Other", Source = "API", Identifier = 131185 }, + { Type = "Performance", Source = "API", Identifier = 131186 }, --Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" + { Type = "Deprecated", Source = "API", Identifier = 7} -- API_ID_LINE_WIDTH deprecated behavior warning has been generated + }, +-- FilterSeverity = { } + + } + --RenderingMethod = "ABuffer" -- alternative: "Framebuffer" +} From 3520e42097baaaf76bda685a726b2028680b7a3c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 8 Jul 2017 16:30:19 -0400 Subject: [PATCH 145/192] Correctly position Screenspace renderable if a scene tag is specified --- src/rendering/screenspacerenderable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index b059566dac..860c066325 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -310,7 +310,7 @@ glm::mat4 ScreenSpaceRenderable::scaleMatrix() { glm::mat4 ScreenSpaceRenderable::rotationMatrix() { // Get the scene transform - glm::mat4 rotation = OsEng.windowWrapper().modelMatrix(); + glm::mat4 rotation = glm::inverse(OsEng.windowWrapper().modelMatrix()); if (!_useEuclideanCoordinates) { glm::vec2 position = _sphericalPosition.value(); From 1cf53d5479bf9623bafc3f82b764ee97e7c83314 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 8 Jul 2017 17:11:50 -0400 Subject: [PATCH 146/192] Make console work with Fisheye rendering --- src/engine/openspaceengine.cpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 5a88b5092f..8d807b705f 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1102,27 +1102,20 @@ void OpenSpaceEngine::render(const glm::mat4& sceneMatrix, const glm::mat4& viewMatrix, const glm::mat4& projectionMatrix) { - bool isGuiWindow = _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; - bool showOverlay = isGuiWindow && _windowWrapper->isMaster() && _windowWrapper->isRegularRendering(); - // @CLEANUP: Replace the two windows by a single call to whether a gui should be - // rendered ---abock + LTRACE("OpenSpaceEngine::render(begin)"); - if (showOverlay) { + const bool isGuiWindow = + _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; + if (isGuiWindow) { _console->update(); } - LTRACE("OpenSpaceEngine::render(begin)"); _renderEngine->render(sceneMatrix, viewMatrix, projectionMatrix); for (const auto& func : _moduleCallbacks.render) { func(); } - if (showOverlay) { - _renderEngine->renderScreenLog(); - _console->render(); - } - if (_shutdown.inShutdown) { _renderEngine->renderShutdownInformation(_shutdown.timer, _shutdown.waitTime); } @@ -1135,6 +1128,14 @@ void OpenSpaceEngine::postDraw() { _renderEngine->postDraw(); + const bool isGuiWindow = + _windowWrapper->hasGuiWindow() ? _windowWrapper->isGuiWindow() : true; + + if (isGuiWindow) { + _renderEngine->renderScreenLog(); + _console->render(); + } + for (const auto& func : _moduleCallbacks.postDraw) { func(); } From 23a97e982b1ad25204e3a8f2858cbaca875d7fe3 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 10 Jul 2017 13:48:00 -0400 Subject: [PATCH 147/192] Remove the SIMD project and thus remove the dependency on NASM --- support/cmake/support_macros.cmake | 38 ++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/support/cmake/support_macros.cmake b/support/cmake/support_macros.cmake index cc58e7e47d..84ea5c5877 100644 --- a/support/cmake/support_macros.cmake +++ b/support/cmake/support_macros.cmake @@ -165,27 +165,45 @@ function (add_external_dependencies) set(SGCT_BUILD_CSHARP_PROJECTS OFF CACHE BOOL "" FORCE) set(SGCT_LIGHT_ONLY ON CACHE BOOL "" FORCE) set(SGCT_CUSTOMOUTPUTDIRS OFF CACHE BOOL "" FORCE) + set(JPEG_TURBO_WITH_SIMD OFF CACHE BOOL "" FORCE) add_subdirectory(${OPENSPACE_EXT_DIR}/sgct) target_include_directories(libOpenSpace SYSTEM PUBLIC ${OPENSPACE_EXT_DIR}/sgct/include) target_link_libraries( libOpenSpace - # sgct sgct_light glew glfw png16_static quat tinyxml2static turbojpeg-static vrpn ${GLFW_LIBRARIES} ) set_property(TARGET sgct_light PROPERTY FOLDER "External") - set_property(TARGET glew PROPERTY FOLDER "External/SGCT") - set_property(TARGET glfw PROPERTY FOLDER "External/SGCT") - set_property(TARGET png16_static PROPERTY FOLDER "External/SGCT") - set_property(TARGET quat PROPERTY FOLDER "External/SGCT") - set_property(TARGET simd PROPERTY FOLDER "External/SGCT") - set_property(TARGET tinyxml2static PROPERTY FOLDER "External/SGCT") - set_property(TARGET turbojpeg-static PROPERTY FOLDER "External/SGCT") - set_property(TARGET vrpn PROPERTY FOLDER "External/SGCT") - set_property(TARGET zlibstatic PROPERTY FOLDER "External/SGCT") + if (TARGET glew) + set_property(TARGET glew PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET glfw) + set_property(TARGET glfw PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET png16_static) + set_property(TARGET png16_static PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET quat) + set_property(TARGET quat PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET simd) + set_property(TARGET simd PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET tinyxml2static) + set_property(TARGET tinyxml2static PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET turbojpeg-static) + set_property(TARGET turbojpeg-static PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET vrpn) + set_property(TARGET vrpn PROPERTY FOLDER "External/SGCT") + endif () + if (TARGET zlibstatic) + set_property(TARGET zlibstatic PROPERTY FOLDER "External/SGCT") + endif () if (UNIX AND (NOT APPLE)) target_link_libraries(libOpenSpace Xcursor Xinerama X11) From 2d1661679c7863abd68af40b6b20d65129d42176 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Mon, 10 Jul 2017 11:53:15 -0600 Subject: [PATCH 148/192] Replace ${SGCT} token with ${CONFIG} in Launcher and OpenSpaceEngine. --- apps/Launcher/mainwindow.cpp | 2 +- src/engine/openspaceengine.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/Launcher/mainwindow.cpp b/apps/Launcher/mainwindow.cpp index 51fe2e9207..8f16781d49 100644 --- a/apps/Launcher/mainwindow.cpp +++ b/apps/Launcher/mainwindow.cpp @@ -285,7 +285,7 @@ void MainWindow::initialize() { _syncWidget->setSceneFiles(_sceneFiles); // Load all available configuration files - QString configurationDirectory = QString::fromStdString(absPath("${SGCT}")); + QString configurationDirectory = QString::fromStdString(absPath("${CONFIG}")); d = QDir(configurationDirectory); d.setFilter(QDir::Files); list = d.entryInfoList(); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 8d807b705f..a0e932332c 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -88,7 +88,7 @@ using namespace ghoul::cmdparser; namespace { const char* _loggerCat = "OpenSpaceEngine"; - const char* SgctDefaultConfigFile = "${SGCT}/single.xml"; + const char* SgctDefaultConfigFile = "${CONFIG}/single.xml"; const char* SgctConfigArgumentCommand = "-config"; From 00ef5b2fd3e3e1e10e9e889bcba3dbfb13e00912 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Mon, 10 Jul 2017 12:10:01 -0600 Subject: [PATCH 149/192] Add .gitignore-ed, empty logs directory. --- logs/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 logs/.gitignore diff --git a/logs/.gitignore b/logs/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From a82c873927867d7ccd91f9679be6b8b72ad35d97 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Mon, 10 Jul 2017 12:30:08 -0600 Subject: [PATCH 150/192] Adds ${LOGS} path token and LogDir attribute --- openspace.cfg | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openspace.cfg b/openspace.cfg index 526eaec369..b35fe07d09 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -48,7 +48,8 @@ return { CONFIG = "${BASE_PATH}/config", CACHE = "${BASE_PATH}/cache", FONTS = "${OPENSPACE_DATA}/fonts", - DOCUMENTATION = "${BASE_PATH}/documentation" + DOCUMENTATION = "${BASE_PATH}/documentation", + LOGS = "${BASE_PATH}/logs" }, Fonts = { Mono = "${FONTS}/Droid_Sans_Mono/DroidSansMono.ttf", @@ -56,6 +57,7 @@ return { Console = "${FONTS}/Inconsolata/Inconsolata-Regular.ttf" }, Logging = { + LogDir = "${LOGS}", -- LogLevel = "Trace", LogLevel = "Debug", ImmediateFlush = true, From 84547397a743c42bbefa2a20e3d5ddd856fdaa93 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Mon, 10 Jul 2017 12:31:38 -0600 Subject: [PATCH 151/192] Remove trailing spaces --- openspace.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openspace.cfg b/openspace.cfg index b35fe07d09..3a311c0075 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -10,7 +10,7 @@ return { SGCTConfig = sgct.config.single{}, -- A regular 1920x1080 window - -- SGCTConfig = sgct.config.single{1920, 1080}, + -- SGCTConfig = sgct.config.single{1920, 1080}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, @@ -19,7 +19,7 @@ return { -- SGCTConfig = sgct.config.fisheye{1024, 1024, res={4096, 4096}, quality="2k", tilt=27}, -- Streaming OpenSpace via Spout to OBS - -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, + -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, --SGCTConfig = "${CONFIG}/openvr_oculusRiftCv1.xml", From 4f903ac03010172531941002c6d2076264edbfd1 Mon Sep 17 00:00:00 2001 From: Kalle Bladin Date: Mon, 10 Jul 2017 20:34:39 +0200 Subject: [PATCH 152/192] Feature/globebrowsing (#334) Layer support for globe browsing: Add layers using the function openspace.globebrowsing.addLayer Delete layers using openspace.globebrowsing.deleteLayer Layer type does not necessarily have to be of tile type. For example solidcolor does not use tiles Blend modes for layers are Normal, Add, Subtract, Multiply, Color Layer adjustments to affect layers. The current only active one is chroma key to cut out a color from the layer. Transfer functions or clipping masks are examples of layer adjustments for the future. Support for adding layer specifications for quickly accessing GIBS layers: openspace.globebrowsing.createGibsGdalXml openspace.globebrowsing.createTemporalGibsGdalXml The arguments for these functions are currently strings. Would it be better to use a lua dictionary? No data values for height layers are correctly regarded (can be seen on Earth. No longer bumps on the poles) Other minor things: Worked a bit on point globe to render globes at large distances. Currently not in use and doesn't have anything to do with the other things. Concurrent job manager takes a thread pool as argument and not a pointer to one. This is because the concurrent job manager needs to have ownership of the thread pool for correct deinitialization. Will cause breaking change for users of concurrent job manager if merged in to master. * Add ability to add layers programatically. * Clean up * Fix order of deletion in concurrent job manager and clean up * Can create by level tile provider with empty dictionary. * Add script to add GIBS datasets. * Start working with layer adjustment * Update mod files * More work on point globe * Add script to create temporal GIBS datasets. * Update temporal tile provider to be able to take gdal descriptions without file path. * Add adjustment property to layers. * Rename adjustment layer * Add adjustment code to all layer groups * Remove caching of gdal datasets due to cluttering of folders * Document layer support * Update Mars mod * Make Mercury great again. * Cleanup and add blend mode Color * Enable setting of layeradjustment and blend mode from mod files. * No more use for grayscale color overlays. Use grayscale layer with color blend mode instead. * Clean up mod files * Clean up * Clean up * No need for grayscale layers. Reading grayscale in to rgb instead for color layers. * Remove unused layer groups * Correctly read to grayscale layers * Update globe mod files * Rename ColorOverlays to Overlays. * Clean up * Clean up * Solve compilation error --- data/scene/lodglobes/earth/earth.mod | 46 +- .../ESRI/ESRI_Imagery_World_2D.wms | 5 - .../map_service_configs/ESRI/TERRAIN.wms | 12 - .../map_service_configs/GIBS/Coastlines.xml | 6 - .../GIBS/GIBS_Aqua_MODIS_true.xml | 5 - ...MODIS_Terra_Brightness_Temp_Band31_Day.xml | 5 - ...S_Terra_CorrectedReflectance_TrueColor.xml | 5 - .../GIBS/MODIS_Water_Mask.xml | 8 +- .../GIBS/Reference_Features.xml | 6 - .../GIBS/Reference_Labels.xml | 6 - .../GIBS/VIIRS_CityLights_2012.xml | 6 - ...RS_SNPP_CorrectedReflectance_TrueColor.xml | 6 - .../other/frmt_wms_virtualearth.xml | 1 - .../lodglobes/jupiter/callisto/callisto.mod | 7 - .../scene/lodglobes/jupiter/europa/europa.mod | 7 - .../lodglobes/jupiter/ganymede/ganymede.mod | 7 - data/scene/lodglobes/jupiter/io/io.mod | 6 - .../lodglobes/jupiter/jupiter/jupiter.mod | 6 - .../mars/map_service_configs/CTX_Mosaic.xml | 8 +- .../map_service_configs/Mola_Elevation.xml | 5 - .../map_service_configs/Utah/CTX_Mosaic.xml | 2 + .../Utah/MolaCTX_Elevation.xml | 5 - data/scene/lodglobes/mars/mars.mod | 114 +-- .../map_service_configs/OnMercuryColor.xml | 1 + data/scene/lodglobes/mercury/mercury.mod | 74 ++ .../moon/map_service_configs/OnMoonColor.xml | 7 +- .../moon/map_service_configs/OnMoonHeight.xml | 5 - data/scene/lodglobes/moon/moon.mod | 27 +- data/scene/lodglobes/neptune/neptune.mod | 7 - data/scene/lodglobes/saturn/saturn.mod | 7 - data/scene/lodglobes/uranus/uranus.mod | 7 - data/scene/lodglobes/venus/venus.mod | 7 - modules/globebrowsing/CMakeLists.txt | 15 +- modules/globebrowsing/cache/lrucache.h | 1 + modules/globebrowsing/cache/lrucache.inl | 5 + .../cache/memoryawaretilecache.cpp | 2 +- .../availabletiledataevaluator.cpp | 2 +- modules/globebrowsing/globebrowsingmodule.cpp | 107 ++- modules/globebrowsing/globebrowsingmodule.h | 11 +- .../globebrowsing/globebrowsingmodule_lua.inl | 141 ++++ .../globebrowsing/globes/chunkedlodglobe.cpp | 28 +- modules/globebrowsing/globes/pointglobe.cpp | 80 +- modules/globebrowsing/globes/pointglobe.h | 4 + .../globebrowsing/globes/renderableglobe.cpp | 17 +- .../globebrowsing/globes/renderableglobe.h | 3 + .../other/concurrentjobmanager.h | 4 +- .../other/concurrentjobmanager.inl | 6 +- .../globebrowsing/other/distanceswitch.cpp | 41 +- modules/globebrowsing/other/distanceswitch.h | 13 +- modules/globebrowsing/other/lruthreadpool.h | 2 + modules/globebrowsing/other/lruthreadpool.inl | 11 +- .../other/prioritizingconcurrentjobmanager.h | 7 +- .../prioritizingconcurrentjobmanager.inl | 12 +- modules/globebrowsing/other/threadpool.cpp | 9 +- modules/globebrowsing/other/threadpool.h | 2 + .../rendering/gpu/gpuheightlayer.cpp | 2 +- .../globebrowsing/rendering/gpu/gpulayer.cpp | 40 +- .../globebrowsing/rendering/gpu/gpulayer.h | 5 + .../rendering/gpu/gpulayeradjustment.cpp | 64 ++ .../rendering/gpu/gpulayeradjustment.h | 56 ++ .../globebrowsing/rendering/layer/layer.cpp | 278 ++++++- modules/globebrowsing/rendering/layer/layer.h | 55 +- .../rendering/layer/layeradjustment.cpp | 134 ++++ .../layer/layeradjustment.h} | 55 +- .../rendering/layer/layergroup.cpp | 63 +- .../rendering/layer/layergroup.h | 8 +- .../rendering/layer/layergroupid.h | 121 ++- .../rendering/layer/layermanager.cpp | 83 +- .../rendering/layer/layermanager.h | 10 +- .../rendering/layer/layerrendersettings.cpp | 32 +- .../rendering/layer/layerrendersettings.h | 6 + .../rendering/layershadermanager.cpp | 49 +- .../rendering/layershadermanager.h | 4 + .../globebrowsing/scripts/layer_support.lua | 130 ++- modules/globebrowsing/shaders/blending.hglsl | 2 +- .../globebrowsing/shaders/pointglobe_fs.glsl | 25 +- .../globebrowsing/shaders/pointglobe_vs.glsl | 29 +- .../shaders/texturetilemapping.hglsl | 295 +++---- modules/globebrowsing/shaders/tile.hglsl | 9 + .../globebrowsing/shaders/tilefragcolor.hglsl | 30 +- .../tile/asynctiledataprovider.cpp | 27 +- .../tile/asynctiledataprovider.h | 5 + .../gdalrawtiledatareader.cpp | 742 ++++++++++-------- .../rawtiledatareader/rawtiledatareader.cpp | 13 +- .../tile/tileprovider/cachingtileprovider.cpp | 191 ----- .../tile/tileprovider/defaulttileprovider.cpp | 255 ++++++ ...ngtileprovider.h => defaulttileprovider.h} | 20 +- .../presentationslideprovider.cpp | 4 + .../tileprovider/projectiontileprovider.cpp | 385 --------- .../tile/tileprovider/singleimageprovider.cpp | 20 +- .../tile/tileprovider/singleimageprovider.h | 5 +- .../sizereferencetileprovider.cpp | 6 +- .../tileprovider/temporaltileprovider.cpp | 174 ++-- .../tile/tileprovider/temporaltileprovider.h | 13 +- .../tileprovider/tileindextileprovider.cpp | 2 +- .../tile/tileprovider/tileprovider.cpp | 7 +- .../tile/tileprovider/tileprovider.h | 4 +- .../tile/tileprovider/tileproviderbyindex.cpp | 33 +- .../tile/tileprovider/tileproviderbylevel.cpp | 63 +- .../tile/tileprovider/tileproviderbylevel.h | 2 + modules/globebrowsing/tile/tileselector.cpp | 8 +- modules/onscreengui/src/renderproperties.cpp | 4 +- tests/test_concurrentjobmanager.inl | 7 +- 103 files changed, 2743 insertions(+), 1781 deletions(-) create mode 100644 data/scene/lodglobes/mercury/mercury.mod create mode 100644 modules/globebrowsing/globebrowsingmodule_lua.inl create mode 100644 modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp create mode 100644 modules/globebrowsing/rendering/gpu/gpulayeradjustment.h create mode 100644 modules/globebrowsing/rendering/layer/layeradjustment.cpp rename modules/globebrowsing/{tile/tileprovider/presentationslideprovider.h => rendering/layer/layeradjustment.h} (64%) delete mode 100644 modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp create mode 100644 modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp rename modules/globebrowsing/tile/tileprovider/{cachingtileprovider.h => defaulttileprovider.h} (86%) delete mode 100644 modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp diff --git a/data/scene/lodglobes/earth/earth.mod b/data/scene/lodglobes/earth/earth.mod index 37a222bf58..b20133580d 100644 --- a/data/scene/lodglobes/earth/earth.mod +++ b/data/scene/lodglobes/earth/earth.mod @@ -70,12 +70,12 @@ return { ColorLayers = { { Name = "ESRI VIIRS Combo", - Type = "ByLevel", + Type = "ByLevelTileLayer", LevelTileProviders = { { MaxLevel = 3, TileProvider = { - Type = "Temporal", + Type = "TemporalTileLayer", Name = "Temporal VIIRS SNPP", FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_CorrectedReflectance_TrueColor.xml", }, }, @@ -90,22 +90,37 @@ return { Enabled = true, }, { - Type = "Temporal", - Name = "Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature", - FilePath = "map_service_configs/GIBS/Temporal_GHRSST_L4_MUR_Sea_Surface_Temperature.xml", + Name = "BMNG", + FilePath = "map_service_configs/Utah/Bmng.wms" }, { - Type = "Temporal", + Type = "TemporalTileLayer", Name = "Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration", FilePath = "map_service_configs/GIBS/Temporal_AMSR2_GCOM_W1_Sea_Ice_Concentration.xml", }, { - Name = "BMNG", - FilePath = "map_service_configs/Utah/Bmng.wms" - } + Type = "TemporalTileLayer", + Name = "MODIS_Terra_Chlorophyll_A", + FilePath = openspace.globebrowsing.createTemporalGibsGdalXml( + "MODIS_Terra_Chlorophyll_A", + "2013-07-02", + "Yesterday", + "1d", + "1km", + "png") + }, + { + Type = "TemporalTileLayer", + Name = "GHRSST_L4_G1SST_Sea_Surface_Temperature", + FilePath = openspace.globebrowsing.createTemporalGibsGdalXml( + "GHRSST_L4_G1SST_Sea_Surface_Temperature", + "2010-06-21", + "Yesterday", + "1d", + "1km", + "png") + }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, NightLayers = { { Name = "Earth at Night 2012", @@ -118,7 +133,7 @@ return { }, }, { - Type = "Temporal", + Type = "TemporalTileLayer", Name = "Temporal Earth at Night", FilePath = "map_service_configs/GIBS/Temporal_VIIRS_SNPP_DayNightBand_ENCC.xml" } @@ -134,7 +149,7 @@ return { FilePath = "map_service_configs/Utah/Gebco.wms", } }, - ColorOverlays = { + Overlays = { { Name = "Coastlines", FilePath = "map_service_configs/GIBS/Coastlines.xml", @@ -148,14 +163,13 @@ return { FilePath = "map_service_configs/GIBS/Reference_Labels.xml", }, { - Type = "TileIndex", + Type = "TileIndexTileLayer", Name = "Tile Indices", }, { - Type = "SizeReference", + Type = "SizeReferenceTileLayer", Name = "Size Reference", Radii = earthEllipsoid, - BackgroundImagePath = "../arrows.png", }, }, HeightLayers = { diff --git a/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms b/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms index d7d7263f5c..7c54ed40f0 100644 --- a/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms +++ b/data/scene/lodglobes/earth/map_service_configs/ESRI/ESRI_Imagery_World_2D.wms @@ -13,10 +13,5 @@ 512 3 5 - - ./GDAL_Cache/ESRI_Imagery_World_2d - 4 - .jpg - false \ No newline at end of file diff --git a/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms b/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms index 3937681945..a4a50c0a83 100644 --- a/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms +++ b/data/scene/lodglobes/earth/map_service_configs/ESRI/TERRAIN.wms @@ -3,19 +3,7 @@ http://198.102.45.23/arcgis/rest/services/worldelevation3d/terrain3d? GCS_Elevation - - -180.0 - 90.0 - 180.0 - -90.0 - bottom - 2 5 - - ./GDAL_Cache/TERRAIN - 4 - .jpg - false diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml index 830e32da8a..120c022a25 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Coastlines.xml @@ -20,10 +20,4 @@ 400 true 5 - - ./GDAL_Cache/Coastlines - 4 - .png - - false diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml index 19bbcdb9c5..1e5ed01815 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/GIBS_Aqua_MODIS_true.xml @@ -17,11 +17,6 @@ 512 3 5 - - ./GDAL_Cache/GIBS_Aqua_MODIS_true - 4 - .jpg - false true 400 diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml index 46a1189c43..7311954847 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_Brightness_Temp_Band31_Day.xml @@ -17,11 +17,6 @@ 512 4 5 - - ./GDAL_Cache/MODIS_Terra_Brightness_Temp_Band31_Day - 4 - .png - false true 400 diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml index a0d82a02b0..3d9b24822d 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Terra_CorrectedReflectance_TrueColor.xml @@ -17,11 +17,6 @@ 512 3 5 - - ./GDAL_Cache/MODIS_Terra_CorrectedReflectance_TrueColor - 4 - .jpg - false true 400 diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml index b3b90a2f48..4abfdde13d 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/MODIS_Water_Mask.xml @@ -17,13 +17,7 @@ 512 4 5 - - ./GDAL_Cache/MODIS_Water_Mask - 4 - .png - - false true - 400 + 400,204,404 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml index 7cb0e23db1..b4874f7db2 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Features.xml @@ -17,12 +17,6 @@ 512 4 5 - - ./GDAL_Cache/Reference_Features - 4 - .png - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml index 2731893a09..5f45a0d424 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/Reference_Labels.xml @@ -17,12 +17,6 @@ 512 4 5 - - ./GDAL_Cache/Reference_Labels - 4 - .png - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml index 8530c80b81..5589007002 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_CityLights_2012.xml @@ -17,12 +17,6 @@ 512 4 5 - - ./GDAL_Cache/VIIRS_CityLights_2012 - 4 - .jpg - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml index b6ffc234fa..d0ff0f3985 100644 --- a/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml +++ b/data/scene/lodglobes/earth/map_service_configs/GIBS/VIIRS_SNPP_CorrectedReflectance_TrueColor.xml @@ -17,12 +17,6 @@ 512 3 5 - - ./GDAL_Cache/VIIRS_SNPP_CorrectedReflectance_TrueColor - 4 - .jpg - - false true 400 true diff --git a/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml b/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml index 3b628e9a89..42946f0a2f 100644 --- a/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml +++ b/data/scene/lodglobes/earth/map_service_configs/other/frmt_wms_virtualearth.xml @@ -3,5 +3,4 @@ http://a${server_num}.ortho.tiles.virtualearth.net/tiles/a${quadkey}.jpeg?g=90 4 - diff --git a/data/scene/lodglobes/jupiter/callisto/callisto.mod b/data/scene/lodglobes/jupiter/callisto/callisto.mod index c86a629158..53b8cee865 100644 --- a/data/scene/lodglobes/jupiter/callisto/callisto.mod +++ b/data/scene/lodglobes/jupiter/callisto/callisto.mod @@ -32,15 +32,8 @@ return { Name = "Callisto Texture", FilePath = "textures/callisto.jpg", Enabled = true, - TilePixelSize = 112, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/europa/europa.mod b/data/scene/lodglobes/jupiter/europa/europa.mod index b3f4c1a8df..720e68d7db 100644 --- a/data/scene/lodglobes/jupiter/europa/europa.mod +++ b/data/scene/lodglobes/jupiter/europa/europa.mod @@ -32,15 +32,8 @@ return { Name = "Europa Texture", FilePath = "textures/europa.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod index 0099a57786..098014cc0c 100644 --- a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod +++ b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod @@ -32,15 +32,8 @@ return { Name = "Ganymede Texture", FilePath = "textures/ganymede.jpg", Enabled = true, - TilePixelSize = 112, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/io/io.mod b/data/scene/lodglobes/jupiter/io/io.mod index 0deb7fae71..dc6b7c2b8e 100644 --- a/data/scene/lodglobes/jupiter/io/io.mod +++ b/data/scene/lodglobes/jupiter/io/io.mod @@ -34,12 +34,6 @@ return { Enabled = true, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/jupiter/jupiter/jupiter.mod b/data/scene/lodglobes/jupiter/jupiter/jupiter.mod index d8a50af4a5..2c6610b3ae 100644 --- a/data/scene/lodglobes/jupiter/jupiter/jupiter.mod +++ b/data/scene/lodglobes/jupiter/jupiter/jupiter.mod @@ -45,12 +45,6 @@ return { Enabled = true, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, } }, diff --git a/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml b/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml index 51fd81ce11..0491a66bd5 100644 --- a/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml +++ b/data/scene/lodglobes/mars/map_service_configs/CTX_Mosaic.xml @@ -12,10 +12,6 @@ 256 256 - - ./GDAL_CTX_cache - 3 - .png - - false + 400,204,404 + true \ No newline at end of file diff --git a/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml b/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml index 9c440826b0..c003ebf07d 100644 --- a/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml +++ b/data/scene/lodglobes/mars/map_service_configs/Mola_Elevation.xml @@ -10,10 +10,5 @@ -90.0 bottom - - ./GDAL_MOLA_cache - 3 - .png - false \ No newline at end of file diff --git a/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml b/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml index 6135ce51b0..164ab0eb2f 100644 --- a/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml +++ b/data/scene/lodglobes/mars/map_service_configs/Utah/CTX_Mosaic.xml @@ -17,4 +17,6 @@ 256 2 10 + 400,204,404 + true \ No newline at end of file diff --git a/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml b/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml index 96c96f84d7..baa437174c 100644 --- a/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml +++ b/data/scene/lodglobes/mars/map_service_configs/Utah/MolaCTX_Elevation.xml @@ -10,10 +10,5 @@ -90.0 bottom - - ./GDAL_MOLA_cache - 3 - .png - false \ No newline at end of file diff --git a/data/scene/lodglobes/mars/mars.mod b/data/scene/lodglobes/mars/mars.mod index e25290d1c0..7443aa8f2f 100644 --- a/data/scene/lodglobes/mars/mars.mod +++ b/data/scene/lodglobes/mars/mars.mod @@ -1,4 +1,5 @@ local marsEllipsoid = {3396190.0, 3396190.0, 3376200.0} + return { -- Barycenter module { @@ -34,7 +35,8 @@ return { CameraMinHeight = 10, SegmentsPerPatch = 90, -- Allows camera to go down 10000 meters below the reference ellipsoid - InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values + -- Useful when having negative height map values + InteractionDepthBelowEllipsoid = 10000, Layers = { ColorLayers = { { @@ -42,87 +44,30 @@ return { FilePath = "map_service_configs/MARS_Viking_MDIM21.xml", Enabled = true, }, - -- { - -- Type = "SingleImage", - -- Name = "Debug Tiles", - -- FilePath = "../../debugglobe/textures/test_tile.png", - -- }, - --{ - -- Name = "MARS_Viking", - -- FilePath = "map_service_configs/MARS_Viking_MDIM21.xml", - -- Enabled = true, - --}, { Name = "MOLA Pseudo Color", FilePath = "map_service_configs/Utah/MolaPseudoColor.xml", - -- Enabled = true, - }, - --[[ - { - Name = "Mars Viking Clr", - FilePath = "map_datasets/Viking/Mars_Viking_ClrMosaic_global_925m_longlat_full.vrt", - Enabled = true, - }, - ]] - }, - GrayScaleLayers = { - - }, - GrayScaleColorOverlays = { - { - Name = "CTX Mosaic [AWS]", - FilePath = "map_service_configs/CTX.wms", - Enabled = true, }, { Name = "CTX Mosaic [Europe]", FilePath = "map_service_configs/CTX_Mosaic.xml", - --Enabled = true, + BlendMode = "Color" }, { Name = "CTX Mosaic [Utah]", FilePath = "map_service_configs/Utah/CTX_Mosaic.xml", + BlendMode = "Color" }, - { - Name = "West Candor Chasma", - FilePath = "map_datasets/CTX/West_Candor_Chasma_longlat_global.vrt", - --Enabled = true, - }, - { - Name = "Layered Rock Outcrops in Southwest Candor Chasma", - FilePath = "map_datasets/HiRISE/Layered_Rock_Outcrops_in_Southwest_Candor_Chasma_Texture.vrt", - }, - --[[{ - Name = "Themis IR Day", - FilePath = "map_service_configs/Utah/ThemisIRDay.xml", - }, - { - Name = "Themis IR Night", - FilePath = "map_service_configs/Utah/ThemisIRNight.xml", - }, - - { - Name = "MER_Meridianni_Endeavor_Basemap_25cm", - FilePath = "map_datasets/Basemap/MER_Meridianni_Endeavor_Basemap_25cm.vrt", - }, - { - Name = "Part of Area Traversed by the Mars Exploration Rover", - FilePath = "map_datasets/HiRISE/Part_of_Area_Traversed_by_the_Mars_Exploration_Rover_Texture.vrt", - }, - ]] }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { + Overlays = { { - Type = "TileIndex", + Type = "TileIndexTileLayer", Name = "Indices", }, { - Type = "SizeReference", + Type = "SizeReferenceTileLayer", Name = "Size Reference", Radii = marsEllipsoid, - BackgroundImagePath = "../arrows.png", }, }, HeightLayers = { @@ -131,50 +76,7 @@ return { FilePath = "map_service_configs/Mola_Elevation.xml", Enabled = true, TilePixelSize = 90, - DoPreProcessing = true, }, - --[[ - { - Name = "Mola Elevation [Utah]", - FilePath = "map_service_configs/Utah/Mola_Elevation.xml", - Enabled = false, - TilePixelSize = 90, - DoPreProcessing = true, - }, - { - Name = "Mola Elevation CTX", - FilePath = "map_service_configs/Utah/MolaCTX_Elevation.xml", - -- Enabled = true, - TilePixelSize = 90, - DoPreProcessing = true, - },]] - { - Name = "West Candor Chasma", - FilePath = "map_datasets/CTX/West_Candor_Chasma_DEM_longlat_global.vrt", - --Enabled = true, - TilePixelSize = 90, - DoPreProcessing = true, - }, - { - Name = "Layered Rock Outcrops in Southwest Candor Chasma", - FilePath = "map_datasets/HiRISE/Layered_Rock_Outcrops_in_Southwest_Candor_Chasma_Heightmap.vrt", - TilePixelSize = 90, - DoPreProcessing = true, - }, - --[[ - { - Name = "West Candor Chasma", - FilePath = "map_datasets/CTX/West_Candor_Chasma_DEM_longlat_global.vrt", - --Enabled = true, - TilePixelSize = 90, - DoPreProcessing = true, - },]] - --[[ - { - Name = "Part of Area Traversed by the Mars Exploration Rover", - FilePath = "map_datasets/HiRISE/Part_of_Area_Traversed_by_the_Mars_Exploration_Rover_Heightmap.vrt", - }, - ]] }, }, } diff --git a/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml b/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml index d53cb3ad5e..4083bfbba8 100644 --- a/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml +++ b/data/scene/lodglobes/mercury/map_service_configs/OnMercuryColor.xml @@ -25,6 +25,7 @@ 1 top + 5 512 512 \ No newline at end of file diff --git a/data/scene/lodglobes/mercury/mercury.mod b/data/scene/lodglobes/mercury/mercury.mod new file mode 100644 index 0000000000..531b855ba7 --- /dev/null +++ b/data/scene/lodglobes/mercury/mercury.mod @@ -0,0 +1,74 @@ +return { + -- Barycenter module + { + Name = "MercuryBarycenter", + Parent = "SolarSystemBarycenter", + Transform = { + Translation = { + Type = "SpiceTranslation", + Body = "MERCURY", + Observer = "SUN", + Kernels = "${OPENSPACE_DATA}/spice/de430_1850-2150.bsp" + }, + }, + }, + -- RenderableGlobe module + { + Name = "Mercury", + Parent = "MercuryBarycenter", + Transform = { + Rotation = { + Type = "SpiceRotation", + SourceFrame = "IAU_MERCURY", + DestinationFrame = "GALACTIC", + }, + Scale = { + Type = "StaticScale", + Scale = 1, + }, + }, + Renderable = { + Type = "RenderableGlobe", + Radii = {2439700, 2439700.0, 2439700.0}, + Frame = "IAU_MERCURY", + Body = "MERCURY", + + CameraMinHeight = 300, + InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values + SegmentsPerPatch = 64, + Layers = { + ColorLayers = { + { + Name = "Simple Texture", + FilePath = "textures/mercury.jpg", + Enabled = true, + }, + { + Name = "Messenger_Mosaic", + FilePath = "map_service_configs/Utah/MessengerMosaic.wms" + }, + { + Name = "Messenger_MDIS", + FilePath = "map_service_configs/Utah/MessengerMDIS.wms" + } + }, + }, + }, + }, + -- Trail module + { + Name = "MercuryTrail", + Parent = "SolarSystemBarycenter", + Renderable = { + Type = "RenderableTrailOrbit", + Translation = { + Type = "SpiceTranslation", + Body = "MERCURY", + Observer = "SUN", + }, + Color = {0.6, 0.5, 0.5 }, + Period = 87.968, + Resolution = 100 + } + } +} diff --git a/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml b/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml index d2d9d1ec11..458fdab892 100644 --- a/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml +++ b/data/scene/lodglobes/moon/map_service_configs/OnMoonColor.xml @@ -61,13 +61,8 @@ top 512 - 512 + 512 true 400 true - - ./GDAL_Cache/OnMoonColor - 4 - .png - \ No newline at end of file diff --git a/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml b/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml index e008c2aa90..3f0934091c 100644 --- a/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml +++ b/data/scene/lodglobes/moon/map_service_configs/OnMoonHeight.xml @@ -19,9 +19,4 @@ true 400 true - - ./GDAL_Cache/OnMoonHeight - 4 - .png - \ No newline at end of file diff --git a/data/scene/lodglobes/moon/moon.mod b/data/scene/lodglobes/moon/moon.mod index 1247ae7187..40499d6004 100644 --- a/data/scene/lodglobes/moon/moon.mod +++ b/data/scene/lodglobes/moon/moon.mod @@ -25,12 +25,6 @@ return { InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values Layers = { ColorLayers = { - - }, - GrayScaleColorOverlays = { - - }, - GrayScaleLayers = { { Name = "OnMoonColorGrayscale", FilePath = "map_service_configs/OnMoonColor.xml", @@ -48,29 +42,14 @@ return { Name = "WAC", FilePath = "map_service_configs/Utah/Wac.wms" } - }, - NightLayers = { - - }, - WaterMasks = { - - }, - ColorOverlays = { - }, HeightLayers = { - { - Name = "OnMoonHeight", - FilePath = "map_service_configs/OnMoonHeight.xml", - Enabled = true, - DoPreProcessing = true, - TileSize = 64, - }, { Name = "LolaDem", FilePath = "map_service_configs/Utah/LolaDem.wms", - DoPreProcessing = true, - TileSize = 64, + Enabled = true, + TilePixelSize = 64, + Settings = { Multiplier = 0.5 }, } }, }, diff --git a/data/scene/lodglobes/neptune/neptune.mod b/data/scene/lodglobes/neptune/neptune.mod index cfb74029b9..31bac3a1fe 100644 --- a/data/scene/lodglobes/neptune/neptune.mod +++ b/data/scene/lodglobes/neptune/neptune.mod @@ -40,15 +40,8 @@ return { Name = "Texture", FilePath = "textures/neptune.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/data/scene/lodglobes/saturn/saturn.mod b/data/scene/lodglobes/saturn/saturn.mod index da471b0979..cb04b02d13 100644 --- a/data/scene/lodglobes/saturn/saturn.mod +++ b/data/scene/lodglobes/saturn/saturn.mod @@ -40,15 +40,8 @@ return { Name = "Saturn Texture", FilePath = "textures/saturn.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/data/scene/lodglobes/uranus/uranus.mod b/data/scene/lodglobes/uranus/uranus.mod index 06b2160647..81dd7f8eb3 100644 --- a/data/scene/lodglobes/uranus/uranus.mod +++ b/data/scene/lodglobes/uranus/uranus.mod @@ -40,15 +40,8 @@ return { Name = "Texture", FilePath = "textures/uranus.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/data/scene/lodglobes/venus/venus.mod b/data/scene/lodglobes/venus/venus.mod index 2ac91197ed..6288883665 100644 --- a/data/scene/lodglobes/venus/venus.mod +++ b/data/scene/lodglobes/venus/venus.mod @@ -45,15 +45,8 @@ return { Name = "Venus Texture", FilePath = "textures/venus.jpg", Enabled = true, - TilePixelSize = 256, }, }, - GrayScaleLayers = { }, - GrayScaleColorOverlays = { }, - NightLayers = { }, - WaterMasks = { }, - ColorOverlays = { }, - HeightLayers = { }, }, }, }, diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 786d6ec329..57b8c92a56 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -25,6 +25,8 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/globebrowsingmodule.h + ${CMAKE_CURRENT_SOURCE_DIR}/cache/lrucache.h ${CMAKE_CURRENT_SOURCE_DIR}/cache/lrucache.inl ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawaretilecache.h @@ -79,12 +81,14 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuchunktilepile.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuheightlayer.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayer.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayeradjustment.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayergroup.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayermanager.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayerrendersettings.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputiledepthtransform.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputileuvtransform.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layer.h + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layeradjustment.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layergroup.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layergroupid.h ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layermanager.h @@ -102,8 +106,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileselector.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileuvtransform.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileloadjob.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/cachingtileprovider.h - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.h + ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/defaulttileprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/singleimageprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/sizereferencetileprovider.h ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.h @@ -123,6 +126,9 @@ set(HEADER_FILES ) set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/globebrowsingmodule.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/globebrowsingmodule_lua.inl + ${CMAKE_CURRENT_SOURCE_DIR}/cache/memoryawaretilecache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/cache/texturecontainer.cpp @@ -159,12 +165,14 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuchunktilepile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpuheightlayer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayeradjustment.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayergroup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayermanager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gpulayerrendersettings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputiledepthtransform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/gpu/gputileuvtransform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layeradjustment.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layergroup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layermanager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rendering/layer/layerrendersettings.cpp @@ -178,8 +186,7 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tile/tilemetadata.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileselector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileloadjob.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/cachingtileprovider.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/presentationslideprovider.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/defaulttileprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/singleimageprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/sizereferencetileprovider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile/tileprovider/temporaltileprovider.cpp diff --git a/modules/globebrowsing/cache/lrucache.h b/modules/globebrowsing/cache/lrucache.h index b23cdae9db..8ebf224a9c 100644 --- a/modules/globebrowsing/cache/lrucache.h +++ b/modules/globebrowsing/cache/lrucache.h @@ -70,6 +70,7 @@ public: */ Item popLRU(); size_t size() const; + size_t maximumCacheSize() const; private: void putWithoutCleaning(const KeyType& key, const ValueType& value); diff --git a/modules/globebrowsing/cache/lrucache.inl b/modules/globebrowsing/cache/lrucache.inl index 6141338001..47c0eb4126 100644 --- a/modules/globebrowsing/cache/lrucache.inl +++ b/modules/globebrowsing/cache/lrucache.inl @@ -120,6 +120,11 @@ size_t LRUCache::size() const { return _itemMap.size(); } +template +size_t LRUCache::maximumCacheSize() const { + return _maximumCacheSize; +} + template void LRUCache::putWithoutCleaning(const KeyType& key, const ValueType& value) diff --git a/modules/globebrowsing/cache/memoryawaretilecache.cpp b/modules/globebrowsing/cache/memoryawaretilecache.cpp index e59423515a..98f439f700 100644 --- a/modules/globebrowsing/cache/memoryawaretilecache.cpp +++ b/modules/globebrowsing/cache/memoryawaretilecache.cpp @@ -117,7 +117,7 @@ void MemoryAwareTileCache::clear() { void MemoryAwareTileCache::createDefaultTextureContainers() { for (int id = 0; id < layergroupid::NUM_LAYER_GROUPS; id++) { TileTextureInitData initData = - LayerManager::getTileTextureInitData(layergroupid::ID(id)); + LayerManager::getTileTextureInitData(layergroupid::GroupID(id)); assureTextureContainerExists(initData); } } diff --git a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp b/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp index caaeaac038..8191439767 100644 --- a/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp +++ b/modules/globebrowsing/chunk/chunklevelevaluator/availabletiledataevaluator.cpp @@ -42,7 +42,7 @@ int AvailableTileData::getDesiredLevel(const Chunk& chunk, const RenderData& dat for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { for (const auto& layer : layerManager->layerGroup(i).activeLayers()) { - Tile::Status status = layer->tileProvider()->getTileStatus(chunk.tileIndex()); + Tile::Status status = layer->getTileStatus(chunk.tileIndex()); if (status == Tile::Status::OK) { return UnknownDesiredLevel; } diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 79621716c0..a4d9b9947c 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -37,10 +37,11 @@ #include #include #include -#include + +#include +#include #include -#include #include #include @@ -48,6 +49,8 @@ #include +#include "globebrowsingmodule_lua.inl" + namespace openspace { const std::string GlobeBrowsingModule::name = "GlobeBrowsing"; @@ -59,11 +62,10 @@ GlobeBrowsingModule::GlobeBrowsingModule() void GlobeBrowsingModule::internalInitialize() { using namespace globebrowsing; + // Initialize OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Initialize, [&] { - - _tileCache = std::make_unique(); - addPropertySubOwner(*_tileCache); - + _tileCache = std::make_unique(); + addPropertySubOwner(*_tileCache); #ifdef GLOBEBROWSING_USE_GDAL // Convert from MB to Bytes GdalWrapper::create( @@ -73,37 +75,47 @@ void GlobeBrowsingModule::internalInitialize() { #endif // GLOBEBROWSING_USE_GDAL }); + // Render OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Render, [&]{ _tileCache->update(); }); - + // Deinitialize OsEng.registerModuleCallback(OpenSpaceEngine::CallbackOption::Deinitialize, [&]{ #ifdef GLOBEBROWSING_USE_GDAL GdalWrapper::ref().destroy(); #endif // GLOBEBROWSING_USE_GDAL }); + // Get factories auto fRenderable = FactoryManager::ref().factory(); ghoul_assert(fRenderable, "Renderable factory was not created"); + // Create factory for TileProviders + auto fTileProvider = + std::make_unique>(); + ghoul_assert(fTileProvider, "TileProvider factory was not created"); + + // Register renderable class fRenderable->registerClass("RenderableGlobe"); - // add Tile Provider factory - auto fTileProvider = std::make_unique>(); - - fTileProvider->registerClass("LRUCaching"); - fTileProvider->registerClass("SingleImage"); + // Register TileProvider classes + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::DefaultTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::SingleImageTileLayer)]); #ifdef GLOBEBROWSING_USE_GDAL - fTileProvider->registerClass("Temporal"); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::TemporalTileLayer)]); #endif // GLOBEBROWSING_USE_GDAL - - fTileProvider->registerClass("TileIndex"); - fTileProvider->registerClass("SizeReference"); - - // Combining Tile Providers - fTileProvider->registerClass("ByLevel"); - fTileProvider->registerClass("ByIndex"); - fTileProvider->registerClass("PresentationSlides"); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::TileIndexTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::SizeReferenceTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::ByLevelTileLayer)]); + fTileProvider->registerClass( + layergroupid::LAYER_TYPE_NAMES[static_cast(layergroupid::TypeID::ByIndexTileLayer)]); + FactoryManager::ref().addFactory(std::move(fTileProvider)); } @@ -112,13 +124,62 @@ globebrowsing::cache::MemoryAwareTileCache* GlobeBrowsingModule::tileCache() { } scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { + std::string listLayerGroups = layerGroupNamesList(); return { "globebrowsing", - {}, + { + { + "addLayer", + &globebrowsing::luascriptfunctions::addLayer, + "string, string, table", + "Adds a layer to the specified globe. The first argument specifies the " + "name of the scene graph node of which to add the layer. The renderable " + "of the specified scene graph node needs to be a renderable globe. " + "The second argument is the layer group which can be any of " + + listLayerGroups + ". The third argument is the dictionary defining the " + "layer." + }, + { + "deleteLayer", + &globebrowsing::luascriptfunctions::deleteLayer, + "string, string", + "Removes a layer from the specified globe. The first argument specifies " + "the name of the scene graph node of which to remove the layer. " + "The renderable of the specified scene graph node needs to be a " + "renderable globe. The second argument is the layer group which can be " + "any of " + listLayerGroups + ". The third argument is the dictionary" + "defining the layer." + }, + }, { "${MODULE_GLOBEBROWSING}/scripts/layer_support.lua" + }, + { + // Documentation } }; } +std::string GlobeBrowsingModule::layerGroupNamesList() { + std::string listLayerGroups(""); + for (int i = 0; i < globebrowsing::layergroupid::NUM_LAYER_GROUPS - 1; ++i) { + listLayerGroups += + globebrowsing::layergroupid::LAYER_GROUP_NAMES[i] + std::string(", "); + } + listLayerGroups += + std::string(" and ") + globebrowsing::layergroupid::LAYER_GROUP_NAMES[ + globebrowsing::layergroupid::NUM_LAYER_GROUPS - 1]; + return listLayerGroups; +} + +std::string GlobeBrowsingModule::layerTypeNamesList() { + std::string listLayerTypes(""); + for (int i = 0; i < globebrowsing::layergroupid::NUM_LAYER_TYPES - 1; ++i) { + listLayerTypes += globebrowsing::layergroupid::LAYER_TYPE_NAMES[i] + ", "; + } + listLayerTypes += + " and " + globebrowsing::layergroupid::LAYER_TYPE_NAMES[globebrowsing::layergroupid::NUM_LAYER_TYPES - 1]; + return listLayerTypes; +} + } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index b07b845cb6..a72a4b0fee 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -46,11 +46,20 @@ public: scripting::LuaLibrary luaLibrary() const override; - protected: void internalInitialize() override; private: + /** + \return a comma separated list of layer group names. + */ + static std::string layerGroupNamesList(); + + /** + \return a comma separated list of layer type names. + */ + static std::string layerTypeNamesList(); + std::unique_ptr _tileCache; }; diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl new file mode 100644 index 0000000000..cd6dbfb9f7 --- /dev/null +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -0,0 +1,141 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + + +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace openspace { +namespace globebrowsing { +namespace luascriptfunctions { + +/** + Adds a layer to the specified globe. + */ +int addLayer(lua_State* L) { + using ghoul::lua::errorLocation; + + // Argument locations + const int GlobeLocation = -3; + const int LayerGroupLocation = -2; + const int DictionaryLocation = -1; + + int nArguments = lua_gettop(L); + if (nArguments != 3) { + return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments); + } + + // String arguments + const std::string GlobeName = luaL_checkstring(L, GlobeLocation); + const std::string LayerGroupName = luaL_checkstring(L, LayerGroupLocation); + + // Get the node and make sure it exists + SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(GlobeName); + if (!node) { + return luaL_error(L, ("Unknown globe name: " + GlobeName).c_str()); + } + + // Get the renderable globe + RenderableGlobe* globe = dynamic_cast(node->renderable()); + if (!globe) { + return luaL_error(L, ("Renderable is not a globe: " + GlobeName).c_str()); + } + + // Get the layer group + layergroupid::GroupID groupID = layergroupid::getGroupIDFromName(LayerGroupName); + if (groupID == layergroupid::GroupID::Unknown) { + return luaL_error(L, ("Unknown layer group: " + LayerGroupName).c_str()); + } + + // Get the dictionary defining the layer + ghoul::Dictionary d; + try { + ghoul::lua::luaDictionaryFromState(L, d); + } + catch (const ghoul::lua::LuaFormatException& e) { + LERRORC("addLayerFromDictionary", e.what()); + return 0; + } + + globe->layerManager()->addLayer(groupID, d); + + return 0; +} + +/** + Deletes a layer from the specified globe. + */ +int deleteLayer(lua_State* L) { + using ghoul::lua::errorLocation; + + // Argument locations + const int GlobeLocation = -3; + const int LayerGroupLocation = -2; + const int NameLocation = -1; + + int nArguments = lua_gettop(L); + if (nArguments != 3) { + return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments); + } + + // String arguments + const std::string GlobeName = luaL_checkstring(L, GlobeLocation); + const std::string LayerGroupName = luaL_checkstring(L, LayerGroupLocation); + const std::string LayerName = luaL_checkstring(L, NameLocation); + + // Get the node and make sure it exists + SceneGraphNode* node = OsEng.renderEngine().scene()->sceneGraphNode(GlobeName); + if (!node) { + return luaL_error(L, ("Unknown globe name: " + GlobeName).c_str()); + } + + // Get the renderable globe + RenderableGlobe* globe = dynamic_cast(node->renderable()); + if (!globe) { + return luaL_error(L, ("Renderable is not a globe: " + GlobeName).c_str()); + } + + // Get the layer group + layergroupid::GroupID groupID = layergroupid::getGroupIDFromName(LayerGroupName); + if (groupID == layergroupid::GroupID::Unknown) { + return luaL_error(L, ("Unknown layer group: " + LayerGroupName).c_str()); + } + + globe->layerManager()->deleteLayer(groupID, LayerName); + + return 0; +} + + +} // namespace luascriptfunctions +} // nameapace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/globes/chunkedlodglobe.cpp b/modules/globebrowsing/globes/chunkedlodglobe.cpp index 48fffb6faa..2014f0c20c 100644 --- a/modules/globebrowsing/globes/chunkedlodglobe.cpp +++ b/modules/globebrowsing/globes/chunkedlodglobe.cpp @@ -178,6 +178,9 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { for (const std::shared_ptr& layer : heightMapLayers) { tileprovider::TileProvider* tileProvider = layer->tileProvider(); + if (!tileProvider) { + continue; + } // Transform the uv coordinates to the current tile texture ChunkTile chunkTile = tileProvider->getChunkTile(tileIndex); const Tile& tile = chunkTile.tile; @@ -188,8 +191,9 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { } ghoul::opengl::Texture* tileTexture = tile.texture(); - if (!tileTexture) - return 0; + if (!tileTexture) { + return 0; + } glm::vec2 transformedUv = Tile::TileUvToTextureSamplePosition( uvTransform, @@ -253,12 +257,19 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { float sample = sample0 * (1.0 - samplePosFract.y) + sample1 * samplePosFract.y; - // Perform depth transform to get the value in meters - height = depthTransform.depthOffset + depthTransform.depthScale * sample; - // Make sure that the height value follows the layer settings. - // For example if the multiplier is set to a value bigger than one, - // the sampled height should be modified as well. - height = layer->renderSettings().performLayerSettings(height); + // Same as is used in the shader. This is not a perfect solution but + // if the sample is actually a no-data-value (min_float) the interpolated + // value might not be. Therefore we have a cut-off. Assuming no data value + // is smaller than -100000 + if (sample > -100000) + { + // Perform depth transform to get the value in meters + height = depthTransform.depthOffset + depthTransform.depthScale * sample; + // Make sure that the height value follows the layer settings. + // For example if the multiplier is set to a value bigger than one, + // the sampled height should be modified as well. + height = layer->renderSettings().performLayerSettings(height); + } } // Return the result return height; @@ -346,6 +357,7 @@ void ChunkedLodGlobe::debugRenderChunk(const Chunk& chunk, const glm::dmat4& mvp } void ChunkedLodGlobe::update(const UpdateData& data) { + setBoundingSphere(_owner.ellipsoid().maximumRadius() * data.modelTransform.scale); _renderer->update(); } diff --git a/modules/globebrowsing/globes/pointglobe.cpp b/modules/globebrowsing/globes/pointglobe.cpp index 1de34b1fa7..f1cc79a4c3 100644 --- a/modules/globebrowsing/globes/pointglobe.cpp +++ b/modules/globebrowsing/globes/pointglobe.cpp @@ -38,7 +38,20 @@ namespace globebrowsing { PointGlobe::PointGlobe(const RenderableGlobe& owner) : _owner(owner) -{} + , _intensityClamp( + "intensityClamp", + "Intensity clamp", + 1, 0, 1 + ) + , _lightIntensity( + "lightIntensity", + "Light intensity", + 1, 0, 50 + ) +{ + addProperty(_intensityClamp); + addProperty(_lightIntensity); +} PointGlobe::~PointGlobe() { glDeleteBuffers(1, &_vertexBufferID); @@ -56,21 +69,27 @@ bool PointGlobe::initialize() { glBindVertexArray(_vaoID); - // Vertex data is only one point in the origin - glm::vec3 data = glm::vec3(0,0,0); - + std::array quadVertexData = { + glm::vec2(-1.0f, -1.0f), + glm::vec2(1.0f, -1.0f), + glm::vec2(-1.0f, 1.0f), + glm::vec2(-1.0f, 1.0f), + glm::vec2(1.0f, -1.0f), + glm::vec2(1.0f, 1.0f) + }; + // Vertex buffer glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID); glBufferData( GL_ARRAY_BUFFER, - sizeof(glm::vec3), - &data, + sizeof(glm::vec2) * quadVertexData.size(), + quadVertexData.data(), GL_STATIC_DRAW ); // Position at location 0 glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), 0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2), 0); glBindVertexArray(0); @@ -91,32 +110,55 @@ void PointGlobe::render(const RenderData& data) { // Calculate variables to be used as uniform variables in shader glm::dvec3 bodyPosition = data.modelTransform.translation; + glm::dmat4 rotationTransform = glm::lookAt( + glm::dvec3(0.0f), + data.camera.positionVec3() - bodyPosition, + glm::normalize(glm::dvec3(1000000.0f) - bodyPosition)); + + glm::dvec3 camToBody = bodyPosition - data.camera.positionVec3(); + float distanceToBody = glm::length(camToBody); + + float avgRadius = _owner.ellipsoid().averageRadius(); + float lightIntensity = _lightIntensity.value() * data.modelTransform.scale * avgRadius / distanceToBody; + float lightIntensityClamped = glm::min(lightIntensity, _intensityClamp.value()); + float lightOverflow = glm::max(lightIntensity - lightIntensityClamped, 0.0f); + + float billboardRadius = lightIntensityClamped * distanceToBody; + glm::dmat4 scaleTransform = glm::scale(glm::dmat4(1.0), glm::dvec3(billboardRadius)); + + setBoundingSphere(billboardRadius); + // Model transform and view transform needs to be in double precision glm::dmat4 modelTransform = glm::translate(glm::dmat4(1.0), bodyPosition) * // Translation - glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); // Scale + glm::inverse(rotationTransform) * + scaleTransform; // Scale glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition)); glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun; - int windowWidth = OsEng.windowWrapper().currentWindowSize().x; - float avgRadius = _owner.ellipsoid().averageRadius(); - - _programObject->setUniform("windowWidth", windowWidth); - _programObject->setUniform("globeRadius", avgRadius); - _programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace); + + _programObject->setUniform("lightIntensityClamped", lightIntensityClamped); + //_programObject->setUniform("lightOverflow", lightOverflow); + //_programObject->setUniform("directionToSunViewSpace", directionToSunViewSpace); _programObject->setUniform("modelViewTransform", glm::mat4(modelViewTransform)); _programObject->setUniform("projectionTransform", data.camera.sgctInternal.projectionMatrix()); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glBindVertexArray(_vaoID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vertexBufferID); - glDrawArrays(GL_POINTS, 0, 1); + glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); - + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + _programObject->deactivate(); } diff --git a/modules/globebrowsing/globes/pointglobe.h b/modules/globebrowsing/globes/pointglobe.h index 9750444785..34c28ab6fb 100644 --- a/modules/globebrowsing/globes/pointglobe.h +++ b/modules/globebrowsing/globes/pointglobe.h @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___POINTGLOBE___H__ #include +#include #include @@ -55,6 +56,9 @@ private: GLuint _vertexBufferID; GLuint _vaoID; + + properties::FloatProperty _intensityClamp; + properties::FloatProperty _lightIntensity; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index 72a80d9d3b..f8976b8f58 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -26,6 +26,7 @@ #include #include +#include #include namespace { @@ -78,7 +79,7 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) glm::dvec3 radii; dictionary.getValue(keyRadii, radii); _ellipsoid = Ellipsoid(radii); - setBoundingSphere(_ellipsoid.averageRadius()); + setBoundingSphere(_ellipsoid.maximumRadius()); // Ghoul can't read ints from lua dictionaries... double patchSegmentsd; @@ -105,13 +106,10 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _chunkedLodGlobe = std::make_shared( *this, patchSegments, _layerManager); + //_pointGlobe = std::make_shared(*this); - // This distance will be enough to render the globe as one pixel if the field of - // view is 'fov' radians and the screen resolution is 'res' pixels. - double fov = 2 * glm::pi() / 6; // 60 degrees - int res = 2880; - double distance = res * _ellipsoid.maximumRadius() / tan(fov / 2); - _distanceSwitch.addSwitchValue(_chunkedLodGlobe, distance); + _distanceSwitch.addSwitchValue(_chunkedLodGlobe); + //_distanceSwitch.addSwitchValue(_pointGlobe); addProperty(_generalProperties.isEnabled); addProperty(_generalProperties.atmosphereEnabled); @@ -149,6 +147,7 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) addPropertySubOwner(_debugPropertyOwner); addPropertySubOwner(_layerManager.get()); + //addPropertySubOwner(_pointGlobe.get()); } bool RenderableGlobe::initialize() { @@ -229,6 +228,10 @@ std::shared_ptr RenderableGlobe::chunkedLodGlobe() const{ return _chunkedLodGlobe; } +LayerManager* RenderableGlobe::layerManager() const { + return _layerManager.get(); +} + const Ellipsoid& RenderableGlobe::ellipsoid() const{ return _ellipsoid; } diff --git a/modules/globebrowsing/globes/renderableglobe.h b/modules/globebrowsing/globes/renderableglobe.h index b90e01eec2..ee92df2197 100644 --- a/modules/globebrowsing/globes/renderableglobe.h +++ b/modules/globebrowsing/globes/renderableglobe.h @@ -37,6 +37,7 @@ namespace openspace { namespace globebrowsing { class ChunkedLodGlobe; +class PointGlobe; class LayerManager; /** @@ -93,6 +94,7 @@ public: // Getters std::shared_ptr chunkedLodGlobe() const; + LayerManager* layerManager() const; const Ellipsoid& ellipsoid() const; const glm::dmat4& modelTransform() const; const glm::dmat4& inverseModelTransform() const; @@ -107,6 +109,7 @@ private: // Globes. These are renderables inserted in a distance switch so that the heavier // ChunkedLodGlobe does not have to be rendered at far distances. std::shared_ptr _chunkedLodGlobe; + //std::shared_ptr _pointGlobe; Ellipsoid _ellipsoid; std::shared_ptr _layerManager; diff --git a/modules/globebrowsing/other/concurrentjobmanager.h b/modules/globebrowsing/other/concurrentjobmanager.h index 910a02ef1f..fad0a62704 100644 --- a/modules/globebrowsing/other/concurrentjobmanager.h +++ b/modules/globebrowsing/other/concurrentjobmanager.h @@ -51,7 +51,7 @@ struct Job { template class ConcurrentJobManager { public: - ConcurrentJobManager(std::shared_ptr pool); + ConcurrentJobManager(ThreadPool pool); void enqueueJob(std::shared_ptr> job); @@ -63,8 +63,8 @@ public: private: ConcurrentQueue>> _finishedJobs; - std::shared_ptr threadPool; std::mutex _finishedJobsMutex; + ThreadPool threadPool; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/other/concurrentjobmanager.inl b/modules/globebrowsing/other/concurrentjobmanager.inl index a522216f5b..763f46b848 100644 --- a/modules/globebrowsing/other/concurrentjobmanager.inl +++ b/modules/globebrowsing/other/concurrentjobmanager.inl @@ -34,13 +34,13 @@ template Job

::~Job() {} template -ConcurrentJobManager

::ConcurrentJobManager(std::shared_ptr pool) +ConcurrentJobManager

::ConcurrentJobManager(ThreadPool pool) : threadPool(pool) { } template void ConcurrentJobManager

::enqueueJob(std::shared_ptr> job) { - threadPool->enqueue([this, job]() { + threadPool.enqueue([this, job]() { job->execute(); std::lock_guard lock(_finishedJobsMutex); _finishedJobs.push(job); @@ -49,7 +49,7 @@ void ConcurrentJobManager

::enqueueJob(std::shared_ptr> job) { template void ConcurrentJobManager

::clearEnqueuedJobs() { - threadPool->clearTasks(); + threadPool.clearTasks(); } template diff --git a/modules/globebrowsing/other/distanceswitch.cpp b/modules/globebrowsing/other/distanceswitch.cpp index 1b6ff8349f..aeb95de079 100644 --- a/modules/globebrowsing/other/distanceswitch.cpp +++ b/modules/globebrowsing/other/distanceswitch.cpp @@ -32,7 +32,6 @@ namespace globebrowsing { DistanceSwitch::~DistanceSwitch() {} bool DistanceSwitch::initialize() { - _objectScale = 1.0; for (unsigned int i = 0; i < _renderables.size(); ++i) { _renderables[i]->initialize(); } @@ -46,44 +45,32 @@ bool DistanceSwitch::deinitialize() { return true; } - void DistanceSwitch::render(const RenderData& data) { - if (_maxDistances.size() == 0) { - return; - } - - double distanceToCamera = distance(data.camera.positionVec3(), data.modelTransform.translation); - - if (distanceToCamera > _maxDistances.back() * _objectScale) { - return; - } + const double distanceToCamera = + distance(data.camera.positionVec3(), data.modelTransform.translation); + // This distance will be enough to render the globe as one pixel if the field of + // view is 'fov' radians and the screen resolution is 'res' pixels. + const double fov = 2 * glm::pi() / 6; // 60 degrees + int res = 2880; + // linear search through nodes to find which Renderable to render - for (unsigned int i = 0; i < _renderables.size(); ++i) { - if (distanceToCamera < _maxDistances[i] * _objectScale) { - _renderables[i]->render(data); - return; + for (std::shared_ptr renderable : _renderables) { + const double distance = res * renderable->boundingSphere() / tan(fov / 2); + if (distanceToCamera < distance) { + renderable->render(data); } } } void DistanceSwitch::update(const UpdateData& data) { - _objectScale = data.modelTransform.scale; - for (unsigned int i = 0; i < _renderables.size(); ++i) { - _renderables[i]->update(data); + for (std::shared_ptr renderable : _renderables) { + renderable->update(data); } } -void DistanceSwitch::addSwitchValue(std::shared_ptr renderable, - double maxDistance) -{ - ghoul_assert(maxDistance > 0, "Renderable must have a positive maxDistance"); - if (_maxDistances.size() > 0) { - ghoul_assert(maxDistance > _maxDistances.back(), - "Renderables must be inserted in ascending order wrt distance"); - } +void DistanceSwitch::addSwitchValue(std::shared_ptr renderable) { _renderables.push_back(renderable); - _maxDistances.push_back(maxDistance); } } // namespace globebrowsing diff --git a/modules/globebrowsing/other/distanceswitch.h b/modules/globebrowsing/other/distanceswitch.h index 9f26e35f43..2ba77a9d90 100644 --- a/modules/globebrowsing/other/distanceswitch.h +++ b/modules/globebrowsing/other/distanceswitch.h @@ -39,7 +39,7 @@ namespace globebrowsing { /** * Selects a specific Renderable to be used for rendering, based on distance to the * camera -*/ + */ class DistanceSwitch { public: ~DistanceSwitch(); @@ -50,20 +50,17 @@ public: /** * Picks the first Renderable with the associated maxDistance greater than the * current distance to the camera - */ + */ void render(const RenderData& data); void update(const UpdateData& data); /** - * Adds a new renderable (first argument) which may be rendered only if the distance - * to the camera is less than maxDistance (second argument) - */ - void addSwitchValue(std::shared_ptr renderable, double maxDistance); + * Adds a new renderable + */ + void addSwitchValue(std::shared_ptr renderable); private: std::vector> _renderables; - std::vector _maxDistances; - double _objectScale; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/other/lruthreadpool.h b/modules/globebrowsing/other/lruthreadpool.h index 35a370a179..1b89e04ce1 100644 --- a/modules/globebrowsing/other/lruthreadpool.h +++ b/modules/globebrowsing/other/lruthreadpool.h @@ -33,6 +33,7 @@ #include #include #include +#include // Implementatin based on http://progsch.net/wordpress/?p=81 @@ -65,6 +66,7 @@ template class LRUThreadPool { public: LRUThreadPool(size_t numThreads, size_t queueSize); + LRUThreadPool(const LRUThreadPool& toCopy); ~LRUThreadPool(); void enqueue(std::function f, KeyType key); diff --git a/modules/globebrowsing/other/lruthreadpool.inl b/modules/globebrowsing/other/lruthreadpool.inl index 329767e3bc..bcc57029b5 100644 --- a/modules/globebrowsing/other/lruthreadpool.inl +++ b/modules/globebrowsing/other/lruthreadpool.inl @@ -68,11 +68,18 @@ LRUThreadPool::LRUThreadPool(size_t numThreads, size_t queueSize) } } +template +LRUThreadPool::LRUThreadPool(const LRUThreadPool& toCopy) + : LRUThreadPool(toCopy._workers.size(), toCopy._queuedTasks.maximumCacheSize()) +{ } + // the destructor joins all threads template LRUThreadPool::~LRUThreadPool() { - // Stop all threads - _stop = true; + { + std::unique_lock lock(_queueMutex); + _stop = true; + } _condition.notify_all(); // join them diff --git a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h index f2314b07f5..6b166dd1a2 100644 --- a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h +++ b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.h @@ -43,7 +43,7 @@ namespace globebrowsing { template class PrioritizingConcurrentJobManager { public: - PrioritizingConcurrentJobManager(std::shared_ptr> pool); + PrioritizingConcurrentJobManager(LRUThreadPool pool); /** * Enqueues a job which is identified using a given key @@ -85,9 +85,10 @@ public: private: ConcurrentQueue>> _finishedJobs; - /// An LRU thread pool is used since the jobs can be bumped and hence prioritized. - std::shared_ptr> _threadPool; std::mutex _finishedJobsMutex; + /// An LRU thread pool is used since the jobs can be bumped and hence prioritized. + LRUThreadPool _threadPool; + }; } // namespace globebrowsing diff --git a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl index ebe0147947..dbfbcbefdf 100644 --- a/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl +++ b/modules/globebrowsing/other/prioritizingconcurrentjobmanager.inl @@ -29,7 +29,7 @@ namespace globebrowsing { template PrioritizingConcurrentJobManager::PrioritizingConcurrentJobManager( - std::shared_ptr> pool) + LRUThreadPool pool) : _threadPool(pool) { } @@ -37,7 +37,7 @@ template void PrioritizingConcurrentJobManager::enqueueJob(std::shared_ptr> job, KeyType key) { - _threadPool->enqueue([this, job]() { + _threadPool.enqueue([this, job]() { job->execute(); std::lock_guard lock(_finishedJobsMutex); _finishedJobs.push(job); @@ -47,23 +47,23 @@ void PrioritizingConcurrentJobManager::enqueueJob(std::shared_ptr std::vector PrioritizingConcurrentJobManager::getKeysToUnfinishedJobs() { - return _threadPool->getUnqueuedTasksKeys(); + return _threadPool.getUnqueuedTasksKeys(); } template std::vector PrioritizingConcurrentJobManager::getKeysToEnqueuedJobs() { - return _threadPool->getQueuedTasksKeys(); + return _threadPool.getQueuedTasksKeys(); } template bool PrioritizingConcurrentJobManager::touch(KeyType key) { - return _threadPool->touch(key); + return _threadPool.touch(key); } template void PrioritizingConcurrentJobManager::clearEnqueuedJobs() { - _threadPool->clearEnqueuedTasks(); + _threadPool.clearEnqueuedTasks(); } template diff --git a/modules/globebrowsing/other/threadpool.cpp b/modules/globebrowsing/other/threadpool.cpp index 10de678202..a5a6fb718a 100644 --- a/modules/globebrowsing/other/threadpool.cpp +++ b/modules/globebrowsing/other/threadpool.cpp @@ -67,10 +67,17 @@ ThreadPool::ThreadPool(size_t numThreads) } } +ThreadPool::ThreadPool(const ThreadPool& toCopy) + : ThreadPool(toCopy.workers.size()) +{ } + // the destructor joins all threads ThreadPool::~ThreadPool() { // stop all threads - stop = true; + { + std::unique_lock lock(queue_mutex); + stop = true; + } condition.notify_all(); // join them diff --git a/modules/globebrowsing/other/threadpool.h b/modules/globebrowsing/other/threadpool.h index 97bf25190b..475714086f 100644 --- a/modules/globebrowsing/other/threadpool.h +++ b/modules/globebrowsing/other/threadpool.h @@ -31,6 +31,7 @@ #include #include #include +#include // Implementatin based on http://progsch.net/wordpress/?p=81 @@ -50,6 +51,7 @@ private: class ThreadPool { public: ThreadPool(size_t numThreads); + ThreadPool(const ThreadPool& toCopy); ~ThreadPool(); void enqueue(std::function f); diff --git a/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp b/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp index 5b77c34f9b..ce2fa871ef 100644 --- a/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp +++ b/modules/globebrowsing/rendering/gpu/gpuheightlayer.cpp @@ -38,7 +38,7 @@ void GPUHeightLayer::setValue(ghoul::opengl::ProgramObject* programObject, int pileSize) { GPULayer::setValue(programObject, layer, tileIndex, pileSize); - _gpuDepthTransform.setValue(programObject, layer.tileProvider()->depthTransform()); + _gpuDepthTransform.setValue(programObject, layer.depthTransform()); } void GPUHeightLayer::bind(ghoul::opengl::ProgramObject* programObject, const Layer& layer, diff --git a/modules/globebrowsing/rendering/gpu/gpulayer.cpp b/modules/globebrowsing/rendering/gpu/gpulayer.cpp index e02dd15a45..edfeb457ef 100644 --- a/modules/globebrowsing/rendering/gpu/gpulayer.cpp +++ b/modules/globebrowsing/rendering/gpu/gpulayer.cpp @@ -33,15 +33,51 @@ void GPULayer::setValue(ghoul::opengl::ProgramObject* programObject, const Layer const TileIndex& tileIndex, int pileSize) { ChunkTilePile chunkTilePile = layer.getChunkTilePile(tileIndex, pileSize); - gpuChunkTilePile.setValue(programObject, chunkTilePile); gpuRenderSettings.setValue(programObject, layer.renderSettings()); + gpuLayerAdjustment.setValue(programObject, layer.layerAdjustment()); + + switch (layer.type()) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: + gpuChunkTilePile.setValue(programObject, chunkTilePile); + break; + case layergroupid::TypeID::SolidColor: + gpuColor.setValue(programObject, layer.otherTypesProperties().color.value()); + break; + default: + break; + } } void GPULayer::bind(ghoul::opengl::ProgramObject* programObject, const Layer& layer, const std::string& nameBase, int pileSize) { - gpuChunkTilePile.bind(programObject, nameBase + "pile.", pileSize); gpuRenderSettings.bind(layer.renderSettings(), programObject, nameBase + "settings."); + gpuLayerAdjustment.bind(layer.layerAdjustment(), programObject, nameBase + "adjustment."); + + switch (layer.type()) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: + gpuChunkTilePile.bind(programObject, nameBase + "pile.", pileSize); + break; + case layergroupid::TypeID::SolidColor: + gpuColor.bind(programObject, nameBase + "color"); + break; + default: + break; + } } void GPULayer::deactivate() { diff --git a/modules/globebrowsing/rendering/gpu/gpulayer.h b/modules/globebrowsing/rendering/gpu/gpulayer.h index 3cc2e881c9..746c581b25 100644 --- a/modules/globebrowsing/rendering/gpu/gpulayer.h +++ b/modules/globebrowsing/rendering/gpu/gpulayer.h @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER___H__ #include +#include #include #include #include @@ -73,6 +74,10 @@ public: private: GPUChunkTilePile gpuChunkTilePile; GPULayerRenderSettings gpuRenderSettings; + GPULayerAdjustment gpuLayerAdjustment; + + // Adjustment layer stuff + GPUData gpuColor; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp new file mode 100644 index 0000000000..69ff1707bb --- /dev/null +++ b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.cpp @@ -0,0 +1,64 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +namespace openspace { +namespace globebrowsing { + +void GPULayerAdjustment::setValue(ghoul::opengl::ProgramObject* programObject, + const LayerAdjustment& layerAdjustment) +{ + switch (layerAdjustment.type()) { + case layergroupid::AdjustmentTypeID::None: + break; + case layergroupid::AdjustmentTypeID::ChromaKey: { + gpuChromaKeyColor.setValue(programObject, layerAdjustment.chromaKeyColor.value()); + gpuChromaKeyTolerance.setValue(programObject, layerAdjustment.chromaKeyTolerance.value()); + break; + } + case layergroupid::AdjustmentTypeID::TransferFunction: + break; + } +} + +void GPULayerAdjustment::bind(const LayerAdjustment& layerAdjustment, ghoul::opengl::ProgramObject* programObject, + const std::string& nameBase) +{ + switch (layerAdjustment.type()) { + case layergroupid::AdjustmentTypeID::None: + break; + case layergroupid::AdjustmentTypeID::ChromaKey: { + gpuChromaKeyColor.bind(programObject, nameBase + "chromaKeyColor"); + gpuChromaKeyTolerance.bind(programObject, nameBase + "chromaKeyTolerance"); + break; + } + case layergroupid::AdjustmentTypeID::TransferFunction: + break; + } +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h new file mode 100644 index 0000000000..3a53b8808f --- /dev/null +++ b/modules/globebrowsing/rendering/gpu/gpulayeradjustment.h @@ -0,0 +1,56 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSMENT___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSMENT___H__ + +#include + +namespace ghoul { namespace opengl { +class ProgramObject; +}} + +namespace openspace { +namespace globebrowsing { + +struct LayerAdjustment; + +class GPULayerAdjustment{ +public: + void setValue(ghoul::opengl::ProgramObject* programObject, + const LayerAdjustment& layerAdjustment); + + void bind(const LayerAdjustment& layerAdjustment, + ghoul::opengl::ProgramObject* programObject, + const std::string& nameBase); + +private: + GPUData gpuChromaKeyColor; + GPUData gpuChromaKeyTolerance; +}; + +} // namespace globebrowsing +} // namespace openspace + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GPULAYER_ADJUSMENT___H__ diff --git a/modules/globebrowsing/rendering/layer/layer.cpp b/modules/globebrowsing/rendering/layer/layer.cpp index 5f50476aab..d4f482ba8c 100644 --- a/modules/globebrowsing/rendering/layer/layer.cpp +++ b/modules/globebrowsing/rendering/layer/layer.cpp @@ -30,60 +30,296 @@ namespace openspace { namespace globebrowsing { namespace { + const char* _loggerCat = "Layer"; + const char* keyName = "Name"; const char* keyEnabled = "Enabled"; const char* keyLayerGroupID = "LayerGroupID"; const char* keySettings = "Settings"; + const char* keyAdjustment = "Adjustment"; + const char* KeyBlendMode = "BlendMode"; } -Layer::Layer(layergroupid::ID id, const ghoul::Dictionary& layerDict) +Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict) : properties::PropertyOwner(layerDict.value(keyName)) + , _typeOption( + "type", + "Type", + properties::OptionProperty::DisplayType::Dropdown + ) + , _blendModeOption( + "blendMode", + "Blend Mode", + properties::OptionProperty::DisplayType::Dropdown + ) , _enabled(properties::BoolProperty("enabled", "Enabled", false)) , _reset("reset", "Reset") -{ - // We add the id to the dictionary since it needs to be known by - // the tile provider - ghoul::Dictionary newLayerDict = layerDict; - newLayerDict.setValue(keyLayerGroupID, id); - - _tileProvider = std::shared_ptr( - tileprovider::TileProvider::createFromDictionary(newLayerDict)); - - // Something else went wrong and no exception was thrown - if (_tileProvider == nullptr) { - throw ghoul::RuntimeError("Unable to create TileProvider '" + name() + "'"); + , _tileProvider(nullptr) + , _otherTypesProperties{ + properties::Vec3Property ( + "color", + "Color", + glm::vec4(1.f, 1.f, 1.f, 1.f), + glm::vec4(0.f), + glm::vec4(1.f)) } + , _layerGroupId(id) +{ + layergroupid::TypeID typeID = parseTypeIdFromDictionary(layerDict); + if (typeID == layergroupid::TypeID::Unknown) { + throw ghoul::RuntimeError("Unknown layer type!"); + } + + initializeBasedOnType(typeID, layerDict); bool enabled = false; // defaults to false if unspecified layerDict.getValue(keyEnabled, enabled); _enabled.setValue(enabled); + // Initialize settings ghoul::Dictionary settingsDict; if (layerDict.getValue(keySettings, settingsDict)) { _renderSettings.setValuesFromDictionary(settingsDict); } - if (id == layergroupid::ID::GrayScaleColorOverlays) { - _renderSettings.addProperty(_renderSettings.valueBlending); - _renderSettings.useValueBlending = true; + + // Initiallize layer adjustment + ghoul::Dictionary adjustmentDict; + if (layerDict.getValue(keyAdjustment, adjustmentDict)) { + _layerAdjustment.setValuesFromDictionary(adjustmentDict); } - _reset.onChange([&](){ - _tileProvider->reset(); + // Add options to option properties + for (int i = 0; i < layergroupid::NUM_LAYER_TYPES; ++i) { + _typeOption.addOption(i, layergroupid::LAYER_TYPE_NAMES[i]); + } + _typeOption.setValue(static_cast(typeID)); + _type = static_cast(_typeOption.value()); + + for (int i = 0; i < layergroupid::NUM_BLEND_MODES; ++i) { + _blendModeOption.addOption(i, layergroupid::BLEND_MODE_NAMES[i]); + } + + // Initialize blend mode + std::string blendModeName; + if (layerDict.getValue(KeyBlendMode, blendModeName)) { + layergroupid::BlendModeID blendModeID = + layergroupid::getBlendModeIDFromName(blendModeName); + _blendModeOption.setValue(static_cast(blendModeID)); + } + else { + _blendModeOption.setValue(static_cast(layergroupid::BlendModeID::Normal)); + } + + // On change callbacks definitions + _enabled.onChange([&](){ + if (_onChangeCallback) { + _onChangeCallback(); + } }); + _reset.onChange([&](){ + if (_tileProvider) { + _tileProvider->reset(); + } + }); + + _typeOption.onChange([&](){ + removeVisibleProperties(); + _type = static_cast(_typeOption.value()); + ghoul::Dictionary dict; + initializeBasedOnType(type(), dict); + addVisibleProperties(); + if (_onChangeCallback) { + _onChangeCallback(); + } + }); + + _blendModeOption.onChange([&](){ + if (_onChangeCallback) { + _onChangeCallback(); + } + }); + + _layerAdjustment.onChange([&](){ + if (_onChangeCallback) { + _onChangeCallback(); + } + }); + + _typeOption.setReadOnly(true); + + // Add the properties + addProperty(_typeOption); + addProperty(_blendModeOption); addProperty(_enabled); addProperty(_reset); + _otherTypesProperties.color.setViewOption(properties::Property::ViewOptions::Color); + + addVisibleProperties(); + addPropertySubOwner(_renderSettings); - addPropertySubOwner(*_tileProvider); + addPropertySubOwner(_layerAdjustment); } ChunkTilePile Layer::getChunkTilePile(const TileIndex& tileIndex, int pileSize) const { - return _tileProvider->getChunkTilePile(tileIndex, pileSize); + if (_tileProvider) { + return _tileProvider->getChunkTilePile(tileIndex, pileSize); + } + else { + ChunkTilePile chunkTilePile; + chunkTilePile.resize(pileSize); + for (int i = 0; i < pileSize; ++i) { + chunkTilePile[i].tile = Tile::TileUnavailable; + chunkTilePile[i].uvTransform.uvOffset = { 0, 0 }; + chunkTilePile[i].uvTransform.uvScale = { 1, 1 }; + } + return chunkTilePile; + } +} + +Tile::Status Layer::getTileStatus(const TileIndex& index) const { + if (_tileProvider) { + return _tileProvider->getTileStatus(index); + } + else { + return Tile::Status::Unavailable; + } +} + +layergroupid::TypeID Layer::type() const { + return _type; +}; + +layergroupid::BlendModeID Layer::blendMode() const { + return static_cast(_blendModeOption.value()); +}; + + +TileDepthTransform Layer::depthTransform() const { + if (_tileProvider) { + return _tileProvider->depthTransform(); + } + else { + return {1.0f, 0.0f}; + } +} + +bool Layer::enabled() const { + return _enabled.value(); +} + +tileprovider::TileProvider* Layer::tileProvider() const { + return _tileProvider.get(); +} + +const Layer::OtherTypesProperties& Layer::otherTypesProperties() const { + return _otherTypesProperties; +} + +const LayerRenderSettings& Layer::renderSettings() const { + return _renderSettings; +} + +const LayerAdjustment& Layer::layerAdjustment() const { + return _layerAdjustment; } void Layer::onChange(std::function callback) { - _enabled.onChange(callback); + _onChangeCallback = callback; +} + +void Layer::update() { + if (_tileProvider) { + _tileProvider->update(); + } +} + +layergroupid::TypeID Layer::parseTypeIdFromDictionary( + const ghoul::Dictionary& initDict) const +{ + if (initDict.hasKeyAndValue("Type")) { + const std::string typeString = initDict.value("Type"); + return layergroupid::getTypeIDFromTypeString(typeString); + } + else { + return layergroupid::TypeID::DefaultTileLayer; + } +} + +void Layer::initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict) { + switch (typeId) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: { + // We add the id to the dictionary since it needs to be known by + // the tile provider + ghoul::Dictionary tileProviderInitDict = initDict; + tileProviderInitDict.setValue(keyLayerGroupID, _layerGroupId); + if (tileProviderInitDict.hasKeyAndValue(keyName)) { + std::string name; + tileProviderInitDict.getValue(keyName, name); + LDEBUG("Initializing tile provider for layer: '" + name + "'"); + } + _tileProvider = std::shared_ptr( + tileprovider::TileProvider::createFromDictionary(typeId, tileProviderInitDict) + ); + break; + } + case layergroupid::TypeID::SolidColor: + break; + default: + throw ghoul::RuntimeError("Unable to create layer. Unknown type."); + break; + } +} + +void Layer::addVisibleProperties() { + switch (type()) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: + if (_tileProvider) { + addPropertySubOwner(*_tileProvider); + } + break; + case layergroupid::TypeID::SolidColor: + addProperty(_otherTypesProperties.color); + default: + break; + } +} + +void Layer::removeVisibleProperties() { + switch (type()) { + // Intentional fall through. Same for all tile layers + case layergroupid::TypeID::DefaultTileLayer: + case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SizeReferenceTileLayer: + case layergroupid::TypeID::TemporalTileLayer: + case layergroupid::TypeID::TileIndexTileLayer: + case layergroupid::TypeID::ByIndexTileLayer: + case layergroupid::TypeID::ByLevelTileLayer: + if (_tileProvider) { + removePropertySubOwner(*_tileProvider); + } + break; + case layergroupid::TypeID::SolidColor: + removeProperty(_otherTypesProperties.color); + break; + default: + break; + } } } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/layer/layer.h b/modules/globebrowsing/rendering/layer/layer.h index 437eae8ef2..c8380e5b4f 100644 --- a/modules/globebrowsing/rendering/layer/layer.h +++ b/modules/globebrowsing/rendering/layer/layer.h @@ -25,14 +25,17 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYER___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___LAYER___H__ -#include - #include + +#include #include #include +#include +#include #include #include +#include namespace openspace { namespace globebrowsing { @@ -41,29 +44,55 @@ namespace tileprovider { class TileProvider; } -/** - * Simple struct which is used to enable/disable TileProvider - * and associate is with a name. It also holds layer specific information - * which is used in rendering of layer. - */ class Layer : public properties::PropertyOwner { public: - Layer(layergroupid::ID id, const ghoul::Dictionary& layerDict); + /** + * Properties used when the layer type is not a tile type layer. These properties + * can be added or removed depending on the layer type. + */ + struct OtherTypesProperties { + properties::Vec3Property color; + }; + + Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict); ChunkTilePile getChunkTilePile(const TileIndex& tileIndex, int pileSize) const; + Tile::Status getTileStatus(const TileIndex& index) const; - bool enabled() const { return _enabled.value(); } - tileprovider::TileProvider* tileProvider() const { return _tileProvider.get(); } - const LayerRenderSettings& renderSettings() const { return _renderSettings; } - + layergroupid::TypeID type() const; + layergroupid::BlendModeID blendMode() const; + TileDepthTransform depthTransform() const; + bool enabled() const; + tileprovider::TileProvider* tileProvider() const; + const OtherTypesProperties& otherTypesProperties() const; + const LayerRenderSettings& renderSettings() const; + const LayerAdjustment& layerAdjustment() const; + void onChange(std::function callback); + + void update(); private: + layergroupid::TypeID parseTypeIdFromDictionary(const ghoul::Dictionary& initDict) const; + void initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict); + void addVisibleProperties(); + void removeVisibleProperties(); + + properties::OptionProperty _typeOption; + properties::OptionProperty _blendModeOption; properties::BoolProperty _enabled; properties::TriggerProperty _reset; + + layergroupid::TypeID _type; std::shared_ptr _tileProvider; + OtherTypesProperties _otherTypesProperties; LayerRenderSettings _renderSettings; -}; + LayerAdjustment _layerAdjustment; + + const layergroupid::GroupID _layerGroupId; + + std::function _onChangeCallback; + }; } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/rendering/layer/layeradjustment.cpp b/modules/globebrowsing/rendering/layer/layeradjustment.cpp new file mode 100644 index 0000000000..80b038612b --- /dev/null +++ b/modules/globebrowsing/rendering/layer/layeradjustment.cpp @@ -0,0 +1,134 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace globebrowsing { + +namespace { + const char* keyType = "Type"; + const char* keyChromaKeyColor = "ChromaKeyColor"; + const char* keyChromaKeyTolerance = "ChromaKeyTolerance"; +} + +LayerAdjustment::LayerAdjustment() + : properties::PropertyOwner("adjustment") + , _typeOption( + "type", + "Type", + properties::OptionProperty::DisplayType::Dropdown + ) + , chromaKeyColor( + "chromaKeyColor", + "Chroma key color", + glm::vec3(0.f, 0.f, 0.f), + glm::vec3(0.f), + glm::vec3(1.f) + ) + , chromaKeyTolerance( + "chromaKeyTolerance", + "Chroma key tolerance", + 0, + 0, + 1 + ) + , _onChangeCallback([](){}) +{ + // Add options to option properties + for (int i = 0; i < layergroupid::NUM_ADJUSTMENT_TYPES; ++i) { + _typeOption.addOption(i, layergroupid::ADJUSTMENT_TYPE_NAMES[i]); + } + _typeOption.setValue(static_cast(layergroupid::AdjustmentTypeID::None)); + _type = static_cast(_typeOption.value()); + + _typeOption.onChange([&](){ + removeVisibleProperties(); + _type = static_cast(_typeOption.value()); + addVisibleProperties(); + _onChangeCallback(); + }); + chromaKeyColor.setViewOption(properties::Property::ViewOptions::Color); + + addProperty(_typeOption); + addVisibleProperties(); +} + +void LayerAdjustment::setValuesFromDictionary( + const ghoul::Dictionary& adjustmentDict) +{ + std::string dictType; + glm::vec3 dictChromaKeyColor; + float dictChromaKeyTolerance; + + if (adjustmentDict.getValue(keyType, dictType)) { + _typeOption.setValue( + static_cast(layergroupid::getAdjustmentTypeIDFromName(dictType))); + } + if (adjustmentDict.getValue(keyChromaKeyColor, dictChromaKeyColor)) { + chromaKeyColor.setValue(dictChromaKeyColor); + } + if (adjustmentDict.getValue(keyChromaKeyTolerance, dictChromaKeyTolerance)) { + chromaKeyTolerance.setValue(dictChromaKeyTolerance); + } +} + +layergroupid::AdjustmentTypeID LayerAdjustment::type() const { + return _type; +} + +void LayerAdjustment::addVisibleProperties() { + switch (type()) { + case layergroupid::AdjustmentTypeID::None: + break; + case layergroupid::AdjustmentTypeID::ChromaKey: { + addProperty(chromaKeyColor); + addProperty(chromaKeyTolerance); + break; + } + case layergroupid::AdjustmentTypeID::TransferFunction: + break; + } +} + +void LayerAdjustment::removeVisibleProperties() { + switch (type()) { + case layergroupid::AdjustmentTypeID::None: + break; + case layergroupid::AdjustmentTypeID::ChromaKey: { + removeProperty(chromaKeyColor); + removeProperty(chromaKeyTolerance); + break; + } + case layergroupid::AdjustmentTypeID::TransferFunction: + break; + } +} + +void LayerAdjustment::onChange(std::function callback) { + _onChangeCallback = std::move(callback); +} + +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.h b/modules/globebrowsing/rendering/layer/layeradjustment.h similarity index 64% rename from modules/globebrowsing/tile/tileprovider/presentationslideprovider.h rename to modules/globebrowsing/rendering/layer/layeradjustment.h index 4b331777a1..20b9f11a78 100644 --- a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.h +++ b/modules/globebrowsing/rendering/layer/layeradjustment.h @@ -22,48 +22,51 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ -#define __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_ADJUSTMENT___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_ADJUSTMENT___H__ -#include -#include +#include -#include -#include +#include #include - -#include -#include +#include +#include namespace openspace { namespace globebrowsing { + namespace tileprovider { + class TileProvider; +} -class PresentationSlideProvider : public TileProvider { +class LayerAdjustment : public properties::PropertyOwner +{ public: - PresentationSlideProvider(const ghoul::Dictionary& dictionary); - PresentationSlideProvider(const std::string& imagePath); - virtual ~PresentationSlideProvider() = default; + LayerAdjustment(); + ~LayerAdjustment() = default; - virtual Tile getTile(const TileIndex& tileIndex) override; - virtual Tile::Status getTileStatus(const TileIndex& index) override; - virtual TileDepthTransform depthTransform() override; - virtual void update() override; - virtual void reset() override; - virtual int maxLevel() override; + void setValuesFromDictionary(const ghoul::Dictionary& adjustmentDict); + + layergroupid::AdjustmentTypeID type() const; + + // Properties + properties::Vec3Property chromaKeyColor; + properties::FloatProperty chromaKeyTolerance; + + void onChange(std::function callback); private: - TileProvider* slideProvider(); + void addVisibleProperties(); + void removeVisibleProperties(); + + properties::OptionProperty _typeOption; + layergroupid::AdjustmentTypeID _type; - TileIndex _tileIndex; - properties::IntProperty _slideIndex; - std::vector> _slideProviders; - std::unique_ptr _defaultProvider; + std::function _onChangeCallback; }; -} // namespace tileprovider } // namespace globebrowsing } // namespace openspace -#endif // __OPENSPACE_MODULE_GLOBEBROWSING___PRESENTATION_SLIDE_PROVIDER___H__ +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_ADJUSTMENT___H__ diff --git a/modules/globebrowsing/rendering/layer/layergroup.cpp b/modules/globebrowsing/rendering/layer/layergroup.cpp index 94f5d8cf5d..7b038c8f58 100644 --- a/modules/globebrowsing/rendering/layer/layergroup.cpp +++ b/modules/globebrowsing/rendering/layer/layergroup.cpp @@ -26,35 +26,36 @@ #include +namespace { + const char* _loggerCat = "LayerGroup"; +} + namespace openspace { namespace globebrowsing { -LayerGroup::LayerGroup(std::string name) - : properties::PropertyOwner(std::move(name)) +LayerGroup::LayerGroup(layergroupid::GroupID id) + : properties::PropertyOwner(std::move(layergroupid::LAYER_GROUP_NAMES[id])) + , _groupId(id) , _levelBlendingEnabled("blendTileLevels", "blend tile levels", false) { addProperty(_levelBlendingEnabled); } -LayerGroup::LayerGroup(layergroupid::ID id, const ghoul::Dictionary& dict) - : LayerGroup(layergroupid::LAYER_GROUP_NAMES[id]) +LayerGroup::LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict) + : LayerGroup(id) { for (size_t i = 0; i < dict.size(); i++) { std::string dictKey = std::to_string(i + 1); ghoul::Dictionary layerDict = dict.value(dictKey); try { - _layers.push_back(std::make_shared(id, layerDict)); + addLayer(layerDict); } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); continue; } } - - for (const auto& layer : _layers) { - addPropertySubOwner(layer.get()); - } } void LayerGroup::update() { @@ -62,12 +63,48 @@ void LayerGroup::update() { for (const auto& layer : _layers) { if (layer->enabled()) { - layer->tileProvider()->update(); + layer->update(); _activeLayers.push_back(layer); } } } +void LayerGroup::addLayer(const ghoul::Dictionary& layerDict) { + if (!layerDict.hasKeyAndValue("Name")) { + LERROR("'Name' must be specified for layer."); + return; + } + auto layer = std::make_shared(_groupId, layerDict); + layer->onChange(_onChangeCallback); + if (hasPropertySubOwner(layer->name())) { + LINFO("Layer with name " + layer->name() + " already exists."); + } + else { + _layers.push_back(layer); + update(); + if(_onChangeCallback) { + _onChangeCallback(); + } + addPropertySubOwner(layer.get()); + } +} + +void LayerGroup::deleteLayer(const std::string& layerName) { + for (std::vector>::iterator it = _layers.begin(); it != _layers.end(); ++it) { + if (it->get()->name() == layerName) { + removePropertySubOwner(it->get()); + _layers.erase(it); + update(); + if(_onChangeCallback) { + _onChangeCallback(); + } + LINFO("Deleted layer " + layerName); + return; + } + } + LERROR("Could not find layer " + layerName); +} + const std::vector>& LayerGroup::layers() const { return _layers; } @@ -81,10 +118,10 @@ int LayerGroup::pileSize() const{ } void LayerGroup::onChange(std::function callback) { - _onChangeCallback = callback; - _levelBlendingEnabled.onChange(callback); + _onChangeCallback = std::move(callback); + _levelBlendingEnabled.onChange(_onChangeCallback); for (const std::shared_ptr& layer : _layers) { - layer->onChange(callback); + layer->onChange(_onChangeCallback); } } diff --git a/modules/globebrowsing/rendering/layer/layergroup.h b/modules/globebrowsing/rendering/layer/layergroup.h index d19e9b76d6..8cf6d22d9b 100644 --- a/modules/globebrowsing/rendering/layer/layergroup.h +++ b/modules/globebrowsing/rendering/layer/layergroup.h @@ -47,12 +47,15 @@ namespace tileprovider { * Convenience class for dealing with multiple Layers. */ struct LayerGroup : public properties::PropertyOwner { - LayerGroup(std::string name); - LayerGroup(layergroupid::ID id, const ghoul::Dictionary& dict); + LayerGroup(layergroupid::GroupID id); + LayerGroup(layergroupid::GroupID id, const ghoul::Dictionary& dict); /// Updates all layers tile providers within this group void update(); + void addLayer(const ghoul::Dictionary& layerDict); + void deleteLayer(const std::string& layerName); + /// @returns const vector of all layers const std::vector>& layers() const; @@ -67,6 +70,7 @@ struct LayerGroup : public properties::PropertyOwner { void onChange(std::function callback); private: + const layergroupid::GroupID _groupId; std::vector> _layers; std::vector> _activeLayers; diff --git a/modules/globebrowsing/rendering/layer/layergroupid.h b/modules/globebrowsing/rendering/layer/layergroupid.h index 07b58ca247..8445c4b962 100644 --- a/modules/globebrowsing/rendering/layer/layergroupid.h +++ b/modules/globebrowsing/rendering/layer/layergroupid.h @@ -25,32 +25,133 @@ #ifndef __OPENSPACE_MODULE_GLOBEBROWSING___LAYERGROUPID___H__ #define __OPENSPACE_MODULE_GLOBEBROWSING___LAYERGROUPID___H__ +#include namespace openspace { namespace globebrowsing { namespace layergroupid { -static const int NUM_LAYER_GROUPS = 7; -static const char* LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = { +static const int NUM_LAYER_GROUPS = 5; +static const std::string LAYER_GROUP_NAMES[NUM_LAYER_GROUPS] = { "HeightLayers", "ColorLayers", - "ColorOverlays", - "GrayScaleLayers", - "GrayScaleColorOverlays", + "Overlays", "NightLayers", "WaterMasks" }; -enum ID { +enum GroupID { HeightLayers, ColorLayers, - ColorOverlays, - GrayScaleLayers, - GrayScaleColorOverlays, + Overlays, NightLayers, - WaterMasks + WaterMasks, + Unknown, }; +static const int NUM_LAYER_TYPES = 8; +static const std::string LAYER_TYPE_NAMES[NUM_LAYER_TYPES] = { + "DefaultTileLayer", + "SingleImageTileLayer", + "SizeReferenceTileLayer", + "TemporalTileLayer", + "TileIndexTileLayer", + "ByIndexTileLayer", + "ByLevelTileLayer", + "SolidColor", +}; + +/** + This enumeration is specified explicitly since it is used in the shader as well. + */ +enum class TypeID { + Unknown = -1, + DefaultTileLayer = 0, + SingleImageTileLayer = 1, + SizeReferenceTileLayer = 2, + TemporalTileLayer = 3, + TileIndexTileLayer = 4, + ByIndexTileLayer = 5, + ByLevelTileLayer = 6, + SolidColor = 7, +}; + +static const int NUM_ADJUSTMENT_TYPES = 3; +static const std::string ADJUSTMENT_TYPE_NAMES[NUM_ADJUSTMENT_TYPES] = { + "None", + "ChromaKey", + "TransferFunction", +}; + +/** + This enumeration is specified explicitly since it is used in the shader as well. + */ +enum class AdjustmentTypeID { + None = 0, + ChromaKey = 1, + TransferFunction = 2, +}; + +static const int NUM_BLEND_MODES = 5; +static const std::string BLEND_MODE_NAMES[NUM_BLEND_MODES] = { + "Normal", + "Multiply", + "Add", + "Subtract", + "Color", +}; + +/** + This enumeration is specified explicitly since it is used in the shader as well. + */ +enum class BlendModeID { + Normal = 0, + Multiply = 1, + Add = 2, + Subtract = 3, + Color = 4, +}; + +static TypeID getTypeIDFromTypeString(std::string typeString) { + for (int i = 0; i < NUM_LAYER_TYPES; ++i) { + if (typeString == LAYER_TYPE_NAMES[i]) { + return static_cast(i); + } + } + return TypeID::Unknown; +} + +static layergroupid::GroupID getGroupIDFromName(std::string layerGroupName) { + for (int i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { + if (layerGroupName == layergroupid::LAYER_GROUP_NAMES[i]) { + return static_cast(i); + } + } + return GroupID::Unknown; +} + +static layergroupid::AdjustmentTypeID getAdjustmentTypeIDFromName( + std::string adjustmentTypeName) +{ + for (int i = 0; i < layergroupid::NUM_ADJUSTMENT_TYPES; ++i) { + if (adjustmentTypeName == layergroupid::ADJUSTMENT_TYPE_NAMES[i]) { + return static_cast(i); + } + } + return AdjustmentTypeID::None; +} + +static layergroupid::BlendModeID getBlendModeIDFromName( + std::string blendModeName) +{ + for (int i = 0; i < layergroupid::NUM_BLEND_MODES; ++i) { + if (blendModeName == layergroupid::BLEND_MODE_NAMES[i]) { + return static_cast(i); + } + } + return BlendModeID::Normal; +} + } // namespace layergroupid } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/rendering/layer/layermanager.cpp b/modules/globebrowsing/rendering/layer/layermanager.cpp index df8165bc25..b3f2aabb8a 100644 --- a/modules/globebrowsing/rendering/layer/layermanager.cpp +++ b/modules/globebrowsing/rendering/layer/layermanager.cpp @@ -31,23 +31,38 @@ namespace openspace { namespace globebrowsing { +namespace { + const char* _loggerCat = "LayerManager"; +} + LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) : properties::PropertyOwner("Layers") { - if (layergroupid::NUM_LAYER_GROUPS != layerGroupsDict.size()) { - throw ghoul::RuntimeError( - "Number of Layer Groups must be equal to " + layergroupid::NUM_LAYER_GROUPS); + // First create empty layer groups in case not all are specified + _layerGroups.resize(layergroupid::NUM_LAYER_GROUPS); + for (int i = 0; i < _layerGroups.size(); ++i) { + ghoul::Dictionary emptyDict; + _layerGroups[i] = std::make_shared( + static_cast(i), emptyDict + ); } - // Create all the categories of tile providers - for (size_t i = 0; i < layerGroupsDict.size(); i++) { - const std::string& groupName = layergroupid::LAYER_GROUP_NAMES[i]; - ghoul::Dictionary layerGroupDict = - layerGroupsDict.value(groupName); + std::vector layerGroupNamesInDict = layerGroupsDict.keys(); - _layerGroups.push_back( - std::make_shared( - static_cast(i), layerGroupDict)); + // Create all the layer groups + for (const std::string groupName : layerGroupNamesInDict) { + + layergroupid::GroupID groupId = layergroupid::getGroupIDFromName(groupName); + + if (groupId != layergroupid::GroupID::Unknown) { + ghoul::Dictionary layerGroupDict = + layerGroupsDict.value(groupName); + _layerGroups[static_cast(groupId)] = + std::make_shared(groupId, layerGroupDict); + } + else { + LWARNING("Unknown layer group: " + groupName); + } } for (const std::shared_ptr& layerGroup : _layerGroups) { @@ -55,11 +70,21 @@ LayerManager::LayerManager(const ghoul::Dictionary& layerGroupsDict) } } +void LayerManager::addLayer(layergroupid::GroupID groupId, ghoul::Dictionary layerDict) { + ghoul_assert(groupId != layergroupid::Unknown, "Layer group ID must be known"); + _layerGroups[groupId]->addLayer(layerDict); +} + +void LayerManager::deleteLayer(layergroupid::GroupID groupId, std::string layerName) { + ghoul_assert(groupId != layergroupid::Unknown, "Layer group ID must be known"); + _layerGroups[groupId]->deleteLayer(layerName); +} + const LayerGroup& LayerManager::layerGroup(size_t groupId) { return *_layerGroups[groupId]; } -const LayerGroup& LayerManager::layerGroup(layergroupid::ID groupId) { +const LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) { return *_layerGroups[groupId]; } @@ -92,45 +117,35 @@ void LayerManager::reset(bool includeDisabled) { } } -TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::ID id, +TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::GroupID id, size_t preferredTileSize) { switch (id) { - case layergroupid::ID::HeightLayers: { + case layergroupid::GroupID::HeightLayers: { size_t tileSize = preferredTileSize ? preferredTileSize : 64; return TileTextureInitData(tileSize, tileSize, GL_FLOAT, ghoul::opengl::Texture::Format::Red, TileTextureInitData::ShouldAllocateDataOnCPU::Yes); } - case layergroupid::ID::ColorLayers: { + case layergroupid::GroupID::ColorLayers: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); + ghoul::opengl::Texture::Format::BGRA); } - case layergroupid::ID::ColorOverlays: { + case layergroupid::GroupID::Overlays: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); + ghoul::opengl::Texture::Format::BGRA); } - case layergroupid::ID::GrayScaleLayers: { + case layergroupid::GroupID::NightLayers: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RG); + ghoul::opengl::Texture::Format::BGRA); } - case layergroupid::ID::GrayScaleColorOverlays: { + case layergroupid::GroupID::WaterMasks: { size_t tileSize = preferredTileSize ? preferredTileSize : 512; return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RG); - } - case layergroupid::ID::NightLayers: { - size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); - } - case layergroupid::ID::WaterMasks: { - size_t tileSize = preferredTileSize ? preferredTileSize : 512; - return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, - ghoul::opengl::Texture::Format::RGBA); + ghoul::opengl::Texture::Format::BGRA); } default: { ghoul_assert(false, "Unknown layer group ID"); @@ -138,10 +153,10 @@ TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::ID id, } } -bool LayerManager::shouldPerformPreProcessingOnLayergroup(layergroupid::ID id) { +bool LayerManager::shouldPerformPreProcessingOnLayergroup(layergroupid::GroupID id) { // Only preprocess height layers by default switch (id) { - case layergroupid::ID::HeightLayers: return true; + case layergroupid::GroupID::HeightLayers: return true; default: return false; } } diff --git a/modules/globebrowsing/rendering/layer/layermanager.h b/modules/globebrowsing/rendering/layer/layermanager.h index 22ef5a79a3..454a02d9f8 100644 --- a/modules/globebrowsing/rendering/layer/layermanager.h +++ b/modules/globebrowsing/rendering/layer/layermanager.h @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -45,8 +46,11 @@ class LayerManager : public properties::PropertyOwner { public: LayerManager(const ghoul::Dictionary& textureCategoriesDictionary); + void addLayer(layergroupid::GroupID groupId, ghoul::Dictionary layerDict); + void deleteLayer(layergroupid::GroupID groupId, std::string layerName); + const LayerGroup& layerGroup(size_t groupId); - const LayerGroup& layerGroup(layergroupid::ID); + const LayerGroup& layerGroup(layergroupid::GroupID); bool hasAnyBlendingLayersEnabled() const; @@ -55,10 +59,10 @@ public: void update(); void reset(bool includingDisabled = false); - static TileTextureInitData getTileTextureInitData(layergroupid::ID id, + static TileTextureInitData getTileTextureInitData(layergroupid::GroupID id, size_t preferredTileSize = 0); - static bool shouldPerformPreProcessingOnLayergroup(layergroupid::ID id); + static bool shouldPerformPreProcessingOnLayergroup(layergroupid::GroupID id); void onChange(std::function callback); private: diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp b/modules/globebrowsing/rendering/layer/layerrendersettings.cpp index 6fe1474c58..8cbbd95a79 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.cpp +++ b/modules/globebrowsing/rendering/layer/layerrendersettings.cpp @@ -37,11 +37,12 @@ namespace { LayerRenderSettings::LayerRenderSettings() : properties::PropertyOwner("Settings") - , opacity(properties::FloatProperty("Opacity", "opacity", 1.f, 0.f, 1.f)) - , gamma(properties::FloatProperty("Gamma", "gamma", 1, 0, 5)) - , multiplier(properties::FloatProperty("Multiplier", "multiplier", 1.f, 0.f, 20.f)) - , offset(properties::FloatProperty("Offset", "offset", 0.f, -10000.f, 10000.f)) - , valueBlending(properties::FloatProperty("Value blending", "valueBlending", + , setDefault("setDefault", "Set Default") + , opacity(properties::FloatProperty("opacity", "Opacity", 1.f, 0.f, 1.f)) + , gamma(properties::FloatProperty("gamma", "Gamma", 1, 0, 5)) + , multiplier(properties::FloatProperty("multiplier", "Multiplier", 1.f, 0.f, 20.f)) + , offset(properties::FloatProperty("offset", "Offset", 0.f, -10000.f, 10000.f)) + , valueBlending(properties::FloatProperty("valueBlending", "Value Blending", 1.f, 0.f, 1.f)) , useValueBlending(false) { @@ -50,6 +51,9 @@ LayerRenderSettings::LayerRenderSettings() addProperty(gamma); addProperty(multiplier); addProperty(offset); + addProperty(setDefault); + + setDefault.onChange([this](){ setDefaultValues(); }); } void LayerRenderSettings::setValuesFromDictionary( @@ -62,19 +66,19 @@ void LayerRenderSettings::setValuesFromDictionary( float dictValueBlending; if(renderSettingsDict.getValue(keyOpacity, dictOpacity)) { - opacity.setValue(dictOpacity); + opacity = dictOpacity; } if(renderSettingsDict.getValue(keyGamma, dictGamma)) { - gamma.setValue(dictGamma); + gamma = dictGamma; } if(renderSettingsDict.getValue(keyMultiplier, dictMultiplier)) { - multiplier.setValue(dictMultiplier); + multiplier = dictMultiplier; } if(renderSettingsDict.getValue(keyOffset, dictOffset)) { - multiplier.setValue(dictOffset); + multiplier = dictOffset; } if(renderSettingsDict.getValue(keyValueBlending, dictValueBlending)) { - valueBlending.setValue(dictValueBlending); + valueBlending = dictValueBlending; useValueBlending = true; } } @@ -100,5 +104,13 @@ glm::vec4 LayerRenderSettings::performLayerSettings(glm::vec4 currentValue) cons return newValue; } +void LayerRenderSettings::setDefaultValues() { + opacity = 1.f; + gamma = 1.f; + multiplier = 1.f; + offset = 0.f; + valueBlending = 1.f; +} + } // namespace globebrowsing } // namespace openspace diff --git a/modules/globebrowsing/rendering/layer/layerrendersettings.h b/modules/globebrowsing/rendering/layer/layerrendersettings.h index 2fb4ea2432..95538ee28d 100644 --- a/modules/globebrowsing/rendering/layer/layerrendersettings.h +++ b/modules/globebrowsing/rendering/layer/layerrendersettings.h @@ -28,6 +28,7 @@ #include #include +#include namespace openspace { namespace globebrowsing { @@ -35,6 +36,8 @@ namespace globebrowsing { struct LayerRenderSettings : public properties::PropertyOwner { LayerRenderSettings(); + properties::TriggerProperty setDefault; + properties::FloatProperty opacity; properties::FloatProperty gamma; properties::FloatProperty multiplier; @@ -52,6 +55,9 @@ struct LayerRenderSettings : public properties::PropertyOwner { /// This function matches the function with the same name in the /// shader code glm::vec4 performLayerSettings(glm::vec4 currentValue) const; + +private: + void setDefaultValues(); }; } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/layershadermanager.cpp b/modules/globebrowsing/rendering/layershadermanager.cpp index 0dc6aceb99..502dbbc150 100644 --- a/modules/globebrowsing/rendering/layershadermanager.cpp +++ b/modules/globebrowsing/rendering/layershadermanager.cpp @@ -40,7 +40,10 @@ namespace globebrowsing { bool LayerShaderManager::LayerShaderPreprocessingData::LayerGroupPreprocessingData::operator==( const LayerGroupPreprocessingData& other) const { - return lastLayerIdx == other.lastLayerIdx && + return layerType == other.layerType && + blendMode == other.blendMode && + layerAdjustmentType == other.layerAdjustmentType && + lastLayerIdx == other.lastLayerIdx && layerBlendingEnabled == other.layerBlendingEnabled; } @@ -72,10 +75,19 @@ LayerShaderManager::LayerShaderPreprocessingData for (size_t i = 0; i < layergroupid::NUM_LAYER_GROUPS; i++) { LayerShaderManager::LayerShaderPreprocessingData::LayerGroupPreprocessingData layeredTextureInfo; - auto layerGroup = layerManager->layerGroup(i); + + const LayerGroup& layerGroup = layerManager->layerGroup(i); + std::vector> layers = layerGroup.activeLayers(); + layeredTextureInfo.lastLayerIdx = layerGroup.activeLayers().size() - 1; layeredTextureInfo.layerBlendingEnabled = layerGroup.layerBlendingEnabled(); + for (const std::shared_ptr& layer : layers) { + layeredTextureInfo.layerType.push_back(layer->type()); + layeredTextureInfo.blendMode.push_back(layer->blendMode()); + layeredTextureInfo.layerAdjustmentType.push_back(layer->layerAdjustment().type()); + } + preprocessingData.layeredTextureInfo[i] = layeredTextureInfo; } @@ -153,8 +165,41 @@ void LayerShaderManager::recompileShaderProgram( "blend" + groupName, textureTypes[i].layerBlendingEnabled ); + + // This is to avoid errors from shader preprocessor + std::string keyLayerType = groupName + "0" + "LayerType"; + shaderDictionary.setValue(keyLayerType, 0); + + for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { + std::string key = groupName + std::to_string(j) + "LayerType"; + shaderDictionary.setValue(key, static_cast(textureTypes[i].layerType[j])); + } + + // This is to avoid errors from shader preprocessor + std::string keyBlendMode = groupName + "0" + "BlendMode"; + shaderDictionary.setValue(keyBlendMode, 0); + + for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { + std::string key = groupName + std::to_string(j) + "BlendMode"; + shaderDictionary.setValue(key, static_cast(textureTypes[i].blendMode[j])); + } + + // This is to avoid errors from shader preprocessor + std::string keyLayerAdjustmentType = groupName + "0" + "LayerAdjustmentType"; + shaderDictionary.setValue(keyLayerAdjustmentType, 0); + + for (int j = 0; j < textureTypes[i].lastLayerIdx + 1; ++j) { + std::string key = groupName + std::to_string(j) + "LayerAdjustmentType"; + shaderDictionary.setValue(key, static_cast(textureTypes[i].layerAdjustmentType[j])); + } } + ghoul::Dictionary layerGroupNames; + for (int i = 0; i < layergroupid::NUM_LAYER_GROUPS; ++i) { + layerGroupNames.setValue(std::to_string(i), layergroupid::LAYER_GROUP_NAMES[i]); + } + shaderDictionary.setValue("layerGroups", layerGroupNames); + // Other settings such as "useAtmosphere" auto keyValuePairs = _preprocessingData.keyValuePairs; for (size_t i = 0; i < keyValuePairs.size(); i++) { diff --git a/modules/globebrowsing/rendering/layershadermanager.h b/modules/globebrowsing/rendering/layershadermanager.h index d6712c382b..026e98ecd0 100644 --- a/modules/globebrowsing/rendering/layershadermanager.h +++ b/modules/globebrowsing/rendering/layershadermanager.h @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___LAYER_SHADER_MANAGER___H__ #include +#include #include #include @@ -63,6 +64,9 @@ public: struct LayerGroupPreprocessingData { int lastLayerIdx; bool layerBlendingEnabled; + std::vector layerType; + std::vector blendMode; + std::vector layerAdjustmentType; bool operator==(const LayerGroupPreprocessingData& other) const; }; diff --git a/modules/globebrowsing/scripts/layer_support.lua b/modules/globebrowsing/scripts/layer_support.lua index 576fb52ed0..a1af426327 100644 --- a/modules/globebrowsing/scripts/layer_support.lua +++ b/modules/globebrowsing/scripts/layer_support.lua @@ -8,6 +8,55 @@ openspace.globebrowsing.documentation = { Name = "createHeightLayers", Arguments = "table", Documentation = "Creates a table used in the 'HeightLayers' of a RenderableGlobe." + }, + { + Name = "createTemporalGibsGdalXml", + Arguments = "string, string, string, string, string, string", + Documentation = + "Creates an XML configuration for a temporal GIBS dataset." .. + "Arguments are: Name, Start date, end date, time resolution, time format," .. + "resolution, file format. For all specifications, see " .. + "https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+Available+Imagery+Products" .. + "Usage:" .. + "openspace.globebrowsing.addLayer(" .. + "\"Earth\"," .. + "\"ColorLayers\"," .. + "{" .. + "Type = \"TemporalTileLayer\"," .. + "Name = \"MODIS_Terra_Chlorophyll_A\"," .. + "FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(" .. + "\"MODIS_Terra_Chlorophyll_A\"," .. + "\"2013-07-02\"," .. + "\"Yesterday\"," .. + "\"1d\"," .. + "\"1km\"," .. + "\"png\"" .. + ")" .. + "}" .. + ")" + }, + { + Name = "createGibsGdalXml", + Arguments = "string, string, string, string", + Documentation = + "Creates an XML configuration for a GIBS dataset." .. + "Arguments are: layerName, date, resolution, format." .. + "For all specifications, see " .. + "https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+Available+Imagery+Products" .. + "Usage:" .. + "openspace.globebrowsing.addLayer(" .. + "\"Earth\"," .. + "\"ColorLayers\"," .. + "{" .. + "Name = \"MODIS_Terra_Chlorophyll_A\"," .. + "FilePath = openspace.globebrowsing.createTemporalGibsGdalXml(" .. + "\"MODIS_Terra_Chlorophyll_A\"," .. + "\"2013-07-02\"," .. + "\"1km\"," .. + "\"png\"" .. + ")" .. + "}" .. + ")" } } @@ -31,7 +80,86 @@ end openspace.globebrowsing.createHeightLayers = function (patches) result = {} for k,v in pairs(patches) do - table.insert(result, { Name = v["Name"], FilePath = v["Height"], TilePixelSize = 90, DoPreProcessing = true }) + table.insert(result, { Name = v["Name"], FilePath = v["Height"], TilePixelSize = 90, PerformPreProcessing = true }) end return result end + +openspace.globebrowsing.createTemporalGibsGdalXml = function (layerName, startDate, endDate, timeResolution, resolution, format) + temporalTemplate = + "" .. + "" .. startDate .. "" .. + "" .. endDate .. "" .. + "" .. timeResolution .. "" .. + "YYYY-MM-DD" .. + openspace.globebrowsing.createGibsGdalXml(layerName, "${OpenSpaceTimeId}", resolution, format) .. + "" + return temporalTemplate +end + +openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolution, format) + tileLevel = 5 + -- These resolutions are defined by GIBS: https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+API+for+Developers#GIBSAPIforDevelopers-Script-levelAccessviaGDAL + if resolution == "2km" then + tileLevel = 5 + elseif resolution == "1km" then + tileLevel = 6 + elseif resolution == "500m" then + tileLevel = 7 + elseif resolution == "250m" then + tileLevel = 8 + elseif resolution == "125m" then + tileLevel = 9 + elseif resolution == "62.5m" then + tileLevel = 10 + elseif resolution == "31.25m" then + tileLevel = 11 + elseif resolution == "15.625m" then + tileLevel = 12 + else + openspace.printError("Unknown resolution: " .. resolution) + return "" + end + + rasterCount = 3 + if format == "jpg" then + if layerName == "ASTER_GDEM_Greyscale_Shaded_Relief" then + rasterCount = 1 + else + rasterCount = 3 + end + elseif format == "png" then + rasterCount = 4 + else + openspace.printError("Unknown format \"" .. format .. "\". Use 'jpg' or 'png'") + return "" + end + + gdalWmsTemplate = + "" .. + "" .. + "https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/" .. + layerName .. "/default/" .. date .. "/" .. resolution .. + "/${z}/${y}/${x}." .. format .. "" .. + "" .. + "" .. + "-180.0" .. + "90" .. + "396.0" .. + "-198" .. + "" .. tileLevel .. "" .. + "2" .. + "1" .. + "top" .. + "" .. + "EPSG:4326" .. + "512" .. + "512" .. + "" .. rasterCount .. "" .. + "true" .. + "400,204,404" .. + "true" .. + "" + + return gdalWmsTemplate +end \ No newline at end of file diff --git a/modules/globebrowsing/shaders/blending.hglsl b/modules/globebrowsing/shaders/blending.hglsl index e6b6b64bfd..ce64c9ce84 100644 --- a/modules/globebrowsing/shaders/blending.hglsl +++ b/modules/globebrowsing/shaders/blending.hglsl @@ -25,7 +25,7 @@ #ifndef BLENDING_HGLSL #define BLENDING_HGLSL -vec4 blendOver(vec4 oldColor, vec4 newColor) +vec4 blendNormal(vec4 oldColor, vec4 newColor) { vec4 toReturn; toReturn.rgb = diff --git a/modules/globebrowsing/shaders/pointglobe_fs.glsl b/modules/globebrowsing/shaders/pointglobe_fs.glsl index cafeb66d3b..5977cfddab 100644 --- a/modules/globebrowsing/shaders/pointglobe_fs.glsl +++ b/modules/globebrowsing/shaders/pointglobe_fs.glsl @@ -24,31 +24,22 @@ #include "fragment.glsl" -uniform vec3 directionToSunViewSpace; +//uniform vec3 directionToSunViewSpace; uniform vec3 positionCameraSpace; +//uniform float lightOverflow; in vec4 vs_positionClipSpace; +in vec2 vs_positionModelSpace; Fragment getFragment() { - vec2 pointCoord = (gl_PointCoord.xy - vec2(0.5)) * 2; - pointCoord.y = -pointCoord.y; // y should point up in cam space - if(length(pointCoord) > 1) // Outside of circle radius? - discard; - - // z_coord of sphere - float zCoord = sqrt(1 - pow(length(pointCoord),2)); - - // Light calculations - vec3 normal = normalize(vec3(pointCoord, zCoord)); - float cosTerm = max(dot(directionToSunViewSpace, normal), 0); - - vec3 color = vec3(1,1,1) * 0.7; - vec3 shadedColor = cosTerm * color; - + float alpha = 1 - sqrt(pow(vs_positionModelSpace.x, 2) + pow(vs_positionModelSpace.y, 2)); + alpha = pow(alpha, 3); Fragment frag; - frag.color = vec4(shadedColor,1); + frag.color = vec4(1,1,1, alpha);// + vec4(1,1,1,1) * 0.0000000001 * directionToSunViewSpace.x; + //frag.color *= 1 + (lightOverflow * lightOverflow) * 0.0001; frag.depth = vs_positionClipSpace.w; + frag.blend = BLEND_MODE_ADDITIVE; return frag; } diff --git a/modules/globebrowsing/shaders/pointglobe_vs.glsl b/modules/globebrowsing/shaders/pointglobe_vs.glsl index 011e9bdf07..c68b63d1bf 100644 --- a/modules/globebrowsing/shaders/pointglobe_vs.glsl +++ b/modules/globebrowsing/shaders/pointglobe_vs.glsl @@ -26,29 +26,28 @@ #include "PowerScaling/powerScaling_vs.hglsl" -layout(location = 0) in vec3 in_position; +layout(location = 0) in vec2 in_position; -uniform int windowWidth; -uniform float globeRadius; +uniform float lightIntensityClamped; uniform mat4 modelViewTransform; uniform mat4 projectionTransform; uniform mat4 directionToSunViewSpace; out vec4 vs_positionClipSpace; out vec4 vs_positionCameraSpace; +out vec2 vs_positionModelSpace; void main() { - vec4 positionCameraSpace = modelViewTransform * vec4(in_position, 1); - vs_positionClipSpace = projectionTransform * positionCameraSpace; + vs_positionModelSpace = in_position; - vs_positionClipSpace = z_normalization(vs_positionClipSpace); - - vec4 pointSizeCameraSpace = modelViewTransform * vec4(0,0, in_position.z, 1); - pointSizeCameraSpace.x = globeRadius; - pointSizeCameraSpace.y = globeRadius; - vec4 pointSizeClipSpace = projectionTransform * pointSizeCameraSpace; - vec4 pointSizeNDC = pointSizeClipSpace / pointSizeClipSpace.w; - - gl_PointSize = pointSizeNDC.x * 2 * windowWidth; - gl_Position = vs_positionClipSpace; + float totalIntensity = lightIntensityClamped; + + vec4 positionCameraSpace = modelViewTransform * vec4(in_position * totalIntensity, 0, 1); + + // Position + vec4 positionClipSpace = projectionTransform * positionCameraSpace; + + vs_positionClipSpace = z_normalization(positionClipSpace); + + gl_Position = z_normalization(positionClipSpace); } diff --git a/modules/globebrowsing/shaders/texturetilemapping.hglsl b/modules/globebrowsing/shaders/texturetilemapping.hglsl index a582abf800..42b9bf0551 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.hglsl +++ b/modules/globebrowsing/shaders/texturetilemapping.hglsl @@ -38,10 +38,6 @@ #define USE_COLORTEXTURE #{useColorLayers} #define COLORTEXTURE_BLENDING_ENABLED #{blendColorLayers} -#define NUMLAYERS_GRAYSCALETEXTURE #{lastLayerIndexGrayScaleLayers} + 1 -#define USE_GRAYSCALETEXTURE #{useGrayScaleLayers} -#define GRAYSCALETEXTURE_BLENDING_ENABLED #{blendGrayScaleLayers} - // Third layer type from LayerShaderManager is water mask #define NUMLAYERS_WATERMASK #{lastLayerIndexWaterMasks} + 1 #define USE_WATERMASK #{useWaterMasks} @@ -53,14 +49,9 @@ #define NIGHTTEXTURE_BLENDING_ENABLED #{blendNightLayers} // Fifth layer type from LayerShaderManager is overlay -#define NUMLAYERS_OVERLAY #{lastLayerIndexColorOverlays} + 1 -#define USE_OVERLAY #{useColorOverlays} -#define OVERLAY_BLENDING_ENABLED #{blendColorOverlays} - -// Sixth layer type from LayerShaderManager is grayscale overlay -#define NUMLAYERS_GRAYSCALE_OVERLAY #{lastLayerIndexGrayScaleColorOverlays} + 1 -#define USE_GRAYSCALE_OVERLAY #{useGrayScaleColorOverlays} -#define GRAYSCALE_OVERLAY_BLENDING_ENABLED #{blendGrayScaleColorOverlays} +#define NUMLAYERS_OVERLAY #{lastLayerIndexOverlays} + 1 +#define USE_OVERLAY #{useOverlays} +#define OVERLAY_BLENDING_ENABLED #{blendOverlays} // Global constants #define CHUNK_DEFAULT_HEIGHT #{defaultHeight} @@ -72,32 +63,143 @@ #define SHOW_HEIGHT_RESOLUTION #{showHeightResolution} #define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities} -float performLayerSettings(float currentValue, const LayerSettings settings) { +float performLayerSettingsRGB(float currentValue, const LayerSettings settings) { float newValue = currentValue; newValue = sign(newValue) * pow(abs(newValue), settings.gamma); newValue = newValue * settings.multiplier; newValue = newValue + settings.offset; - newValue = newValue * settings.opacity; return newValue; } +vec4 performLayerSettingsRGB(vec4 currentValue, const LayerSettings settings) { + vec4 newValue = vec4( + performLayerSettingsRGB(currentValue.r, settings), + performLayerSettingsRGB(currentValue.g, settings), + performLayerSettingsRGB(currentValue.b, settings), + currentValue.a); + + return newValue; +} + +float performLayerSettingsAlpha(float currentValue, const LayerSettings settings) { + float newValue = currentValue; + newValue = newValue * settings.opacity; + return newValue; +} + +vec4 performLayerSettingsAlpha(vec4 currentValue, const LayerSettings settings) { + vec4 newValue = currentValue; + newValue.a = performLayerSettingsAlpha(currentValue.a, settings); + return newValue; +} + +float performLayerSettings(float currentValue, const LayerSettings settings) { + float newValue = performLayerSettingsRGB(currentValue, settings); + newValue = performLayerSettingsAlpha(newValue, settings); + return newValue; +} vec4 performLayerSettings(vec4 currentValue, const LayerSettings settings) { - vec4 newValue = vec4( - performLayerSettings(currentValue.r, settings), - performLayerSettings(currentValue.g, settings), - performLayerSettings(currentValue.b, settings), - performLayerSettings(currentValue.a, settings)); - + vec4 newValue = performLayerSettingsRGB(currentValue, settings); + newValue = performLayerSettingsAlpha(newValue, settings); return newValue; } + +#for id, layerGroup in layerGroups +#for i in 0..#{lastLayerIndex#{layerGroup}} + +vec4 getSample#{layerGroup}#{i}( + const vec2 uv, + const LevelWeights levelWeights, + const Layer #{layerGroup}[#{lastLayerIndex#{layerGroup}} + 1]) +{ + vec4 color = vec4(0,0,0,1); + + // All tile layers are the same. Sample from texture +#if (#{#{layerGroup}#{i}LayerType} == 0) // DefaultTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 1) // SingleImageTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 2) // SizeReferenceTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 3) // TemporalTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 4) // TileIndexTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 5) // ByIndexTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 6) // ByLevelTileLayer + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); +#elif (#{#{layerGroup}#{i}LayerType} == 7) // SolidColor + color.rgb = #{layerGroup}[#{i}].color; +#endif + + return color; +} + +#endfor +#endfor + +#for id, layerGroup in layerGroups +#for i in 0..#{lastLayerIndex#{layerGroup}} + +vec4 blend#{layerGroup}#{i}(vec4 currentColor, vec4 newColor, float blendFactor) { +#if (#{#{layerGroup}#{i}BlendMode} == 0) // Default, Normal + return blendNormal(currentColor, vec4(newColor.rgb, newColor.a * blendFactor)); +#elif (#{#{layerGroup}#{i}BlendMode} == 1) // Multiply + return blendMultiply(currentColor, newColor * blendFactor); +#elif (#{#{layerGroup}#{i}BlendMode} == 2) // Add + return blendAdd(currentColor, newColor * blendFactor); +#elif (#{#{layerGroup}#{i}BlendMode} == 3) // Subtract + return blendSubtract(currentColor, newColor * blendFactor); +#elif (#{#{layerGroup}#{i}BlendMode} == 4) // Color + // Convert color to grayscale + float gray = (newColor.r + newColor.g + newColor.b) / 3.0; + + vec3 hsvCurrent = rgb2hsv(currentColor.rgb); + // Use gray from new color as value in hsv + vec3 hsvNew = vec3(hsvCurrent.x, hsvCurrent.y, gray); + vec3 rgbNew = hsv2rgb(hsvNew); + + vec4 color = blendNormal(currentColor, vec4(rgbNew, newColor.a * blendFactor)); + return color; +#endif +} + +#endfor +#endfor + + +#for id, layerGroup in layerGroups +#for i in 0..#{lastLayerIndex#{layerGroup}} + +vec4 performAdjustment#{layerGroup}#{i}(vec4 currentColor, const LayerAdjustment adjustment) { +#if (#{#{layerGroup}#{i}LayerAdjustmentType} == 0) // Default, None + return currentColor; +#elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 1) // ChromaKey + if (distance(currentColor.rgb, adjustment.chromaKeyColor) <= adjustment.chromaKeyTolerance) { + return vec4(0,0,0,0); + } + else { + return currentColor; + } +#elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 2) // TransferFunction + return currentColor; +#else + return currentColor; +#endif +} + +#endfor +#endfor + float calculateUntransformedHeight( vec2 uv, LevelWeights levelWeights, - const Layer HeightTextures[NUMLAYERS_HEIGHTMAP]) { + const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { float height = 0; @@ -107,12 +209,13 @@ float calculateUntransformedHeight( levelWeights = getDefaultLevelWeights(); #endif // HEIGHTMAP_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexHeightLayers} { - height = getTexVal(HeightTextures[#{i}].pile, levelWeights, uv).r; + vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); + colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); + height = colorSample.r; - height = performLayerSettings(height, HeightTextures[#{i}].settings); + height = performLayerSettings(height, HeightLayers[#{i}].settings); } #endfor return height; @@ -121,7 +224,7 @@ float calculateUntransformedHeight( float calculateHeight( vec2 uv, LevelWeights levelWeights, - const Layer HeightTextures[NUMLAYERS_HEIGHTMAP]) { + const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { float height = 0; @@ -134,11 +237,13 @@ float calculateHeight( #for i in 0..#{lastLayerIndexHeightLayers} { - float untransformedHeight = getTexVal(HeightTextures[#{i}].pile, levelWeights, uv).r; + vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); + colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); + float untransformedHeight = colorSample.r; - float heightSample = getTransformedTexVal(HeightTextures[#{i}].depthTransform, untransformedHeight); + float heightSample = getTransformedTexVal(HeightLayers[#{i}].depthTransform, untransformedHeight); if (heightSample > -100000) { - heightSample = performLayerSettings(heightSample, HeightTextures[#{i}].settings); + heightSample = performLayerSettings(heightSample, HeightLayers[#{i}].settings); height = heightSample; } } @@ -162,45 +267,17 @@ vec4 calculateColor( #for i in 0..#{lastLayerIndexColorLayers} { - vec4 colorSample = getTexVal(ColorLayers[#{i}].pile, levelWeights, uv); - + vec4 colorSample = getSampleColorLayers#{i}(uv, levelWeights, ColorLayers); + colorSample = performAdjustmentColorLayers#{i}(colorSample, ColorLayers[#{i}].adjustment); colorSample = performLayerSettings(colorSample, ColorLayers[#{i}].settings); - color = blendOver(color, colorSample); + color = blendColorLayers#{i}(color, colorSample, 1.0); } #endfor return color; } -vec4 calculateGrayScale( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer GrayScaleLayers[NUMLAYERS_GRAYSCALETEXTURE]) { - - vec4 colorGrayScale = currentColor; - - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 -#if !GRAYSCALETEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); -#endif // GRAYSCALE_OVERLAY_BLENDING_ENABLED - - #for i in 0..#{lastLayerIndexGrayScaleLayers} - { - vec4 colorSample = getTexVal(GrayScaleLayers[#{i}].pile, levelWeights, uv); - - colorSample = vec4(colorSample.r, colorSample.r, colorSample.r, 1); - colorSample = performLayerSettings(colorSample, GrayScaleLayers[#{i}].settings); - - colorGrayScale = blendOver(colorGrayScale, colorSample); - } - #endfor - - return colorGrayScale; -} - float gridDots(vec2 uv, vec2 gridResolution){ vec2 uvVertexSpace = fract((gridResolution) * uv) + 0.5; @@ -223,7 +300,6 @@ float tileResolution(vec2 tileUV, const ChunkTile chunkTile){ return gridDots(uv, heightResolution); } - vec4 calculateNight( const vec4 currentColor, const vec2 uv, @@ -233,6 +309,7 @@ vec4 calculateNight( const vec3 lightDirectionCameraSpace) { vec4 nightColor = vec4(0,0,0,0); + vec4 color = currentColor; // The shader compiler will remove unused code when variables are multiplied by // a constant 0 @@ -240,23 +317,23 @@ vec4 calculateNight( levelWeights = getDefaultLevelWeights(); #endif // NIGHTTEXTURE_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexNightLayers} - { - vec4 colorSample = getTexVal(NightLayers[#{i}].pile, levelWeights, uv); - colorSample = performLayerSettings(colorSample, NightLayers[#{i}].settings); - - nightColor = blendOver(nightColor, colorSample); - } - #endfor - - vec3 n = normalize(ellipsoidNormalCameraSpace); vec3 l = lightDirectionCameraSpace; - float cosineFactor = clamp(dot(l, normalize(n + 0.15 * l)) * 3 , 0, 1); - // Blend shaded color with base color - vec4 color = vec4(currentColor.rgb + (cosineFactor) * nightColor.xyz, currentColor.a); + #for i in 0..#{lastLayerIndexNightLayers} + { + vec4 colorSample = getSampleNightLayers#{i}(uv, levelWeights, NightLayers); + colorSample = performAdjustmentNightLayers#{i}(colorSample, NightLayers[#{i}].adjustment); + colorSample = performLayerSettings(colorSample, NightLayers[#{i}].settings); + + float adjustedAlpha = cosineFactor * colorSample.a; + // Filter to night side + vec4 newColor = vec4(cosineFactor * colorSample.xyz, adjustedAlpha); + + color = blendNightLayers#{i}(currentColor, newColor, adjustedAlpha); + } + #endfor return color; } @@ -282,7 +359,7 @@ vec4 calculateOverlay( const vec4 currentColor, const vec2 uv, LevelWeights levelWeights, - const Layer ColorOverlays[NUMLAYERS_OVERLAY]) { + const Layer Overlays[NUMLAYERS_OVERLAY]) { vec4 color = currentColor; @@ -292,67 +369,21 @@ vec4 calculateOverlay( levelWeights = getDefaultLevelWeights(); #endif // OVERLAY_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexColorOverlays} + #for i in 0..#{lastLayerIndexOverlays} { - vec4 colorSample = getTexVal(ColorOverlays[#{i}].pile, levelWeights, uv); - colorSample = performLayerSettings(colorSample, ColorOverlays[#{i}].settings); + vec4 colorSample = getSampleOverlays#{i}(uv, levelWeights, Overlays); + colorSample = performAdjustmentOverlays#{i}(colorSample, Overlays[#{i}].adjustment); - color = blendOver(color, colorSample); + colorSample = performLayerSettings(colorSample, Overlays[#{i}].settings); + + color = blendNormal(color, colorSample); + color = blendOverlays#{i}(color, colorSample, 1.0); } #endfor return color; } -vec4 calculateGrayScaleOverlay( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer GrayScaleColorOverlays[NUMLAYERS_GRAYSCALE_OVERLAY]) { - - vec4 colorGrayScale = currentColor; - // HSV blending - vec3 hsvCurrent = rgb2hsv(currentColor.rgb); - vec4 value = vec4(0,0,0,1); - - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 -#if !GRAYSCALE_OVERLAY_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); -#endif // GRAYSCALE_OVERLAY_BLENDING_ENABLED - - #for i in 0..#{lastLayerIndexGrayScaleColorOverlays} - { - vec4 colorSample = getTexVal(GrayScaleColorOverlays[#{i}].pile, levelWeights, uv); - - colorSample = vec4(colorSample.r, colorSample.r, colorSample.r, colorSample.g); - colorSample = performLayerSettings(colorSample, GrayScaleColorOverlays[#{i}].settings); - - colorGrayScale = blendOver(colorGrayScale, colorSample); - - float valueBlending = GrayScaleColorOverlays[#{i}].settings.valueBlending; - - hsvCurrent.z = colorGrayScale.r * valueBlending + hsvCurrent.z * (1 - valueBlending); - colorGrayScale.rgb = vec3(hsvCurrent.z); - } - #endfor - - vec3 hsvNew = vec3(hsvCurrent.x, hsvCurrent.y, hsvCurrent.z); - vec3 rgbNew = hsv2rgb(hsvNew); -/* - // HSL blending - vec3 hslCurrent = rgb2hsl(currentColor.rgb); - //hslCurrent.y = hslCurrent.z > 0.7 ? 0 : hslCurrent.y; - vec3 hslNew = vec3(hslCurrent.x, hslCurrent.y, colorGrayScale.r); - vec3 rgbNew = hsl2rgb(hslNew); -*/ - // No color blending, use grayscale - //vec3 rgbNew = colorGrayScale.rgb; - vec4 color = blendOver(currentColor, vec4(rgbNew, colorGrayScale.a)); - - return color; -} - vec4 calculateWater( const vec4 currentColor, const vec2 uv, @@ -372,11 +403,13 @@ vec4 calculateWater( #for i in 0..#{lastLayerIndexWaterMasks} { - vec4 colorSample = getTexVal(WaterMasks[#{i}].pile, levelWeights, uv); + vec4 colorSample = getSampleWaterMasks#{i}(uv, levelWeights, WaterMasks); + colorSample = performAdjustmentWaterMasks#{i}(colorSample, WaterMasks[#{i}].adjustment); - colorSample = performLayerSettings(colorSample, WaterMasks[#{i}].settings); + colorSample = performLayerSettingsAlpha(colorSample, WaterMasks[#{i}].settings); + colorSample.a = performLayerSettingsRGB(colorSample.a, WaterMasks[#{i}].settings); - waterColor = blendOver(waterColor, colorSample); + waterColor = blendWaterMasks#{i}(waterColor, colorSample, 1.0); } #endfor @@ -390,7 +423,7 @@ vec4 calculateWater( vec3 specularTotal = specularColor * cosineFactor * specularIntensity * waterColor.a; - //return blendOver(currentColor, waterColor); + //return blendNormal(currentColor, waterColor); return currentColor + vec4(specularTotal, 1); } diff --git a/modules/globebrowsing/shaders/tile.hglsl b/modules/globebrowsing/shaders/tile.hglsl index 9d5e1c79a8..bc93dfcf58 100644 --- a/modules/globebrowsing/shaders/tile.hglsl +++ b/modules/globebrowsing/shaders/tile.hglsl @@ -116,10 +116,19 @@ struct LayerSettings { float valueBlending; }; +struct LayerAdjustment { + vec3 chromaKeyColor; + float chromaKeyTolerance; +}; + struct Layer { ChunkTilePile pile; TileDepthTransform depthTransform; LayerSettings settings; + LayerAdjustment adjustment; + + // Other layer type properties stuff + vec3 color; }; struct LevelWeights { diff --git a/modules/globebrowsing/shaders/tilefragcolor.hglsl b/modules/globebrowsing/shaders/tilefragcolor.hglsl index 6cf772c073..e1dca0d4a9 100644 --- a/modules/globebrowsing/shaders/tilefragcolor.hglsl +++ b/modules/globebrowsing/shaders/tilefragcolor.hglsl @@ -37,22 +37,14 @@ uniform Layer ColorLayers[NUMLAYERS_COLORTEXTURE]; #endif // USE_COLORTEXTURE -#if USE_GRAYSCALETEXTURE -uniform Layer GrayScaleLayers[NUMLAYERS_GRAYSCALETEXTURE]; -#endif // USE_GRAYSCALETEXTURE - #if USE_NIGHTTEXTURE uniform Layer NightLayers[NUMLAYERS_NIGHTTEXTURE]; #endif // USE_NIGHTTEXTURE #if USE_OVERLAY -uniform Layer ColorOverlays[NUMLAYERS_OVERLAY]; +uniform Layer Overlays[NUMLAYERS_OVERLAY]; #endif // USE_OVERLAY -#if USE_GRAYSCALE_OVERLAY -uniform Layer GrayScaleColorOverlays[NUMLAYERS_GRAYSCALE_OVERLAY]; -#endif // USE_GRAYSCALE_OVERLAY - #if USE_WATERMASK uniform Layer WaterMasks[NUMLAYERS_WATERMASK]; #endif // USE_WATERMASK @@ -128,24 +120,6 @@ vec4 getTileFragColor(){ ColorLayers); #endif // USE_COLORTEXTURE -#if USE_GRAYSCALETEXTURE - color = calculateGrayScale( - color, - fs_uv, - levelWeights, - GrayScaleLayers); -#endif // USE_GRAYSCALETEXTURE - -#if USE_GRAYSCALE_OVERLAY - - color = calculateGrayScaleOverlay( - color, - fs_uv, - levelWeights, - GrayScaleColorOverlays); - -#endif // USE_COLORTEXTURE - #if USE_WATERMASK color = calculateWater( color, @@ -203,7 +177,7 @@ vec4 getTileFragColor(){ color, fs_uv, levelWeights, - ColorOverlays); + Overlays); #endif // USE_OVERLAY diff --git a/modules/globebrowsing/tile/asynctiledataprovider.cpp b/modules/globebrowsing/tile/asynctiledataprovider.cpp index 31ece2f257..ec4feedef3 100644 --- a/modules/globebrowsing/tile/asynctiledataprovider.cpp +++ b/modules/globebrowsing/tile/asynctiledataprovider.cpp @@ -47,10 +47,10 @@ AsyncTileDataProvider::AsyncTileDataProvider(const std::string& name, const std::shared_ptr rawTileDataReader) : _name(name) , _rawTileDataReader(rawTileDataReader) - , _concurrentJobManager( - std::make_shared>(1, 10)) + , _concurrentJobManager(LRUThreadPool(1, 10)) , _pboContainer(nullptr) , _resetMode(ResetMode::ShouldResetAllButRawTileDataReader) + , _shouldBeDeleted(false) { _globeBrowsingModule = OsEng.moduleEngine().module(); performReset(ResetRawTileDataReader::No); @@ -176,7 +176,6 @@ void AsyncTileDataProvider::updatePboUsage() { } void AsyncTileDataProvider::update() { - updatePboUsage(); endUnfinishedJobs(); // May reset @@ -203,8 +202,19 @@ void AsyncTileDataProvider::update() { } break; } - case ResetMode::ShouldNotReset: + case ResetMode::ShouldBeDeleted: { + // Clean all finished jobs + getRawTiles(); + // Only allow resetting if there are no jobs currently running + if (_enqueuedTileRequests.size() == 0) { + _shouldBeDeleted = true; + } break; + } + case ResetMode::ShouldNotReset: { + updatePboUsage(); + break; + } default: break; } @@ -219,6 +229,15 @@ void AsyncTileDataProvider::reset() { "'" + _name + "'"); } +void AsyncTileDataProvider::prepairToBeDeleted() { + _resetMode = ResetMode::ShouldBeDeleted; + endEnqueuedJobs(); +} + +bool AsyncTileDataProvider::shouldBeDeleted() { + return _shouldBeDeleted; +} + void AsyncTileDataProvider::performReset(ResetRawTileDataReader resetRawTileDataReader) { ghoul_assert(_enqueuedTileRequests.size() == 0, "No enqueued requests left"); diff --git a/modules/globebrowsing/tile/asynctiledataprovider.h b/modules/globebrowsing/tile/asynctiledataprovider.h index c84c4e5d92..d318eb3851 100644 --- a/modules/globebrowsing/tile/asynctiledataprovider.h +++ b/modules/globebrowsing/tile/asynctiledataprovider.h @@ -76,6 +76,9 @@ public: void update(); void reset(); + void prepairToBeDeleted(); + + bool shouldBeDeleted(); std::shared_ptr getRawTileDataReader() const; float noDataValueAsFloat() const; @@ -86,6 +89,7 @@ protected: enum class ResetMode { ShouldResetAll, ShouldResetAllButRawTileDataReader, + ShouldBeDeleted, ShouldNotReset }; @@ -121,6 +125,7 @@ private: std::set _enqueuedTileRequests; ResetMode _resetMode; + bool _shouldBeDeleted; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp index 8bb8f7edc1..45eaa90a8b 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/gdalrawtiledatareader.cpp @@ -1,339 +1,403 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ -#ifdef GLOBEBROWSING_USE_GDAL - -#include - -#include -#include -#include -#include - -#include -#include // abspath -#include -#include -#include - -#include -#include -#include - -#include - -#include - -namespace { - const std::string _loggerCat = "GdalRawTileDataReader"; -} - -namespace openspace { -namespace globebrowsing { - -std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) { - return os << pr.start.x << ", " << pr.start.y << " with size " << pr.numPixels.x << - ", " << pr.numPixels.y; -} - -GdalRawTileDataReader::GdalRawTileDataReader(const std::string& filePath, - const TileTextureInitData& initData, - const std::string& baseDirectory, - RawTileDataReader::PerformPreprocessing preprocess) - : RawTileDataReader(initData, preprocess) - , _dataset(nullptr) -{ - _initDirectory = baseDirectory.empty() ? CPLGetCurrentDir() : baseDirectory; - _datasetFilePath = filePath; - - { // Aquire lock - std::lock_guard lockGuard(_datasetLock); - initialize(); - } -} - -GdalRawTileDataReader::~GdalRawTileDataReader() { - std::lock_guard lockGuard(_datasetLock); - if (_dataset != nullptr) { - GDALClose(_dataset); - _dataset = nullptr; - } -} - -void GdalRawTileDataReader::reset() { - std::lock_guard lockGuard(_datasetLock); - _cached._maxLevel = -1; - if (_dataset != nullptr) { - GDALClose(_dataset); - _dataset = nullptr; - } - initialize(); -} - -int GdalRawTileDataReader::maxChunkLevel() const { - return _cached._maxLevel; -} - -float GdalRawTileDataReader::noDataValueAsFloat() const { - return _gdalDatasetMetaDataCached.noDataValue; -} - -int GdalRawTileDataReader::rasterXSize() const { - return _gdalDatasetMetaDataCached.rasterXSize; -} - -int GdalRawTileDataReader::rasterYSize() const { - return _gdalDatasetMetaDataCached.rasterYSize; -} - -float GdalRawTileDataReader::depthOffset() const { - return _gdalDatasetMetaDataCached.offset; -} - -float GdalRawTileDataReader::depthScale() const { - return _gdalDatasetMetaDataCached.scale; -} - -std::array GdalRawTileDataReader::getGeoTransform() const { - return _gdalDatasetMetaDataCached.padfTransform; -} - -IODescription GdalRawTileDataReader::getIODescription(const TileIndex& tileIndex) const { - IODescription io; - io.read.region = highestResPixelRegion(tileIndex); - - // write region starts in origin - io.write.region.start = PixelRegion::PixelCoordinate(0, 0); - io.write.region.numPixels = PixelRegion::PixelCoordinate( - _initData.dimensionsWithoutPadding().x, _initData.dimensionsWithoutPadding().y); - - io.read.overview = 0; - io.read.fullRegion = fullPixelRegion(); - // For correct sampling in dataset, we need to pad the texture tile - - PixelRegion scaledPadding = padding; - double scale = - io.read.region.numPixels.x / static_cast(io.write.region.numPixels.x); - scaledPadding.numPixels *= scale; - scaledPadding.start *= scale; - - io.read.region.pad(scaledPadding); - io.write.region.pad(padding); - io.write.region.start = PixelRegion::PixelCoordinate(0, 0); - - io.write.bytesPerLine = _initData.bytesPerLine(); - io.write.totalNumBytes = _initData.totalNumBytes(); - - ghoul_assert(io.write.region.numPixels.x == io.write.region.numPixels.y, ""); - ghoul_assert(io.write.region.numPixels.x == _initData.dimensionsWithPadding().x, ""); - - return io; -} - -void GdalRawTileDataReader::initialize() { - _dataset = openGdalDataset(_datasetFilePath); - - // Assume all raster bands have the same data type - _gdalDatasetMetaDataCached.rasterCount = _dataset->GetRasterCount(); - _gdalDatasetMetaDataCached.scale = _dataset->GetRasterBand(1)->GetScale(); - _gdalDatasetMetaDataCached.offset = _dataset->GetRasterBand(1)->GetOffset(); - _gdalDatasetMetaDataCached.rasterXSize = _dataset->GetRasterXSize(); - _gdalDatasetMetaDataCached.rasterYSize = _dataset->GetRasterYSize(); - _gdalDatasetMetaDataCached.noDataValue = _dataset->GetRasterBand(1)->GetNoDataValue(); - _gdalDatasetMetaDataCached.dataType = tiledatatype::getGdalDataType(_initData.glType()); - - CPLErr err = _dataset->GetGeoTransform(&_gdalDatasetMetaDataCached.padfTransform[0]); - if (err == CE_Failure) { - _gdalDatasetMetaDataCached.padfTransform = RawTileDataReader::getGeoTransform(); - } - - _depthTransform = calculateTileDepthTransform(); - _cached._tileLevelDifference = - calculateTileLevelDifference(_initData.dimensionsWithoutPadding().x); - - int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); - _cached._maxLevel = -_cached._tileLevelDifference; - if (numOverviews > 0) { - _cached._maxLevel += numOverviews - 1; - } -} - -void GdalRawTileDataReader::readImageData( - IODescription& io, RawTile::ReadError& worstError, char* imageDataDest) const { - - // Only read the minimum number of rasters - int nRastersToRead = std::min(_gdalDatasetMetaDataCached.rasterCount, - static_cast(_initData.nRasters())); - - switch (_initData.ghoulTextureFormat()) { - case ghoul::opengl::Texture::Format::Red: - case ghoul::opengl::Texture::Format::RG: - case ghoul::opengl::Texture::Format::RGB: - case ghoul::opengl::Texture::Format::RGBA: { - // Read the data (each rasterband is a separate channel) - for (int i = 0; i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - - RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - break; - } - case ghoul::opengl::Texture::Format::BGR: { - // Read the data (each rasterband is a separate channel) - for (int i = 0; i < 3 && i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - - RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - break; - } - case ghoul::opengl::Texture::Format::BGRA: { - for (int i = 0; i < 3 && i < nRastersToRead; i++) { - // The final destination pointer is offsetted by one datum byte size - // for every raster (or data channel, i.e. R in RGB) - char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); - - RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - if (nRastersToRead > 3) { // Alpha channel exists - // Last read is the alpha channel - char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); - RawTile::ReadError err = repeatedRasterRead(4, io, dataDestination); - - // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 - worstError = std::max(worstError, err); - } - break; - } - default: { - ghoul_assert(false, "Texture format not supported for tiles"); - break; - } - } -} - -RawTile::ReadError GdalRawTileDataReader::rasterRead( - int rasterBand, const IODescription& io, char* dataDestination) const -{ - ghoul_assert(io.read.region.isInside(io.read.fullRegion), "write region of bounds!"); - ghoul_assert( - io.write.region.start.x >= 0 && io.write.region.start.y >= 0, - "Invalid write region" - ); - - PixelRegion::PixelCoordinate end = io.write.region.end(); - size_t largestIndex = - (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _initData.bytesPerPixel(); - ghoul_assert(largestIndex <= io.write.totalNumBytes, "Invalid write region"); - - char* dataDest = dataDestination; - - // GDAL reads pixels top to bottom, but we want our pixels bottom to top. - // Therefore, we increment the destination pointer to the last line on in the - // buffer, and the we specify in the rasterIO call that we want negative line - // spacing. Doing this compensates the flipped Y axis - dataDest += (io.write.totalNumBytes - io.write.bytesPerLine); - - // handle requested write region. Note -= since flipped y axis - dataDest -= io.write.region.start.y * io.write.bytesPerLine; - dataDest += io.write.region.start.x * _initData.bytesPerPixel(); - - GDALRasterBand* gdalRasterBand = _dataset->GetRasterBand(rasterBand); - CPLErr readError = CE_Failure; - readError = gdalRasterBand->RasterIO( - GF_Read, - io.read.region.start.x, // Begin read x - io.read.region.start.y, // Begin read y - io.read.region.numPixels.x, // width to read x - io.read.region.numPixels.y, // width to read y - dataDest, // Where to put data - io.write.region.numPixels.x, // width to write x in destination - io.write.region.numPixels.y, // width to write y in destination - _gdalDatasetMetaDataCached.dataType, // Type - _initData.bytesPerPixel(), // Pixel spacing - -io.write.bytesPerLine // Line spacing - ); - - // Convert error to RawTile::ReadError - RawTile::ReadError error; - switch (readError) { - case CE_None: error = RawTile::ReadError::None; break; - case CE_Debug: error = RawTile::ReadError::Debug; break; - case CE_Warning: error = RawTile::ReadError::Warning; break; - case CE_Failure: error = RawTile::ReadError::Failure; break; - case CE_Fatal: error = RawTile::ReadError::Fatal; break; - default: error = RawTile::ReadError::Failure; break; - } - return error; -} - -GDALDataset* GdalRawTileDataReader::openGdalDataset(const std::string& filePath) { - GDALDataset* dataset = static_cast( - GDALOpen(filePath.c_str(), GA_ReadOnly)); - if (!dataset) { - using namespace ghoul::filesystem; - std::string correctedPath = FileSystem::ref().pathByAppendingComponent( - _initDirectory, filePath - ); - - dataset = static_cast(GDALOpen(correctedPath.c_str(), GA_ReadOnly)); - if (!dataset) { - throw ghoul::RuntimeError("Failed to load dataset:\n" + filePath); - } - } - return dataset; -} - -int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) const { - GDALRasterBand* firstBand = _dataset->GetRasterBand(1); - GDALRasterBand* maxOverview; - int numOverviews = firstBand->GetOverviewCount(); - int sizeLevel0; - if (numOverviews <= 0) { // No overviews. Use first band. - maxOverview = firstBand; - } - else { // Pick the highest overview. - maxOverview = firstBand->GetOverview(numOverviews - 1); - } - sizeLevel0 = maxOverview->GetXSize(); - double diff = log2(minimumPixelSize) - log2(sizeLevel0); - return diff; -} - -} // namespace globebrowsing -} // namespace openspace - -#endif // GLOBEBROWSING_USE_GDAL +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ +#ifdef GLOBEBROWSING_USE_GDAL + +#include + +#include +#include +#include +#include + +#include +#include // abspath +#include +#include +#include + +#include +#include +#include + +#include + +#include + +namespace { + const std::string _loggerCat = "GdalRawTileDataReader"; +} + +namespace openspace { +namespace globebrowsing { + +std::ostream& operator<<(std::ostream& os, const PixelRegion& pr) { + return os << pr.start.x << ", " << pr.start.y << " with size " << pr.numPixels.x << + ", " << pr.numPixels.y; +} + +GdalRawTileDataReader::GdalRawTileDataReader(const std::string& filePath, + const TileTextureInitData& initData, + const std::string& baseDirectory, + RawTileDataReader::PerformPreprocessing preprocess) + : RawTileDataReader(initData, preprocess) + , _dataset(nullptr) +{ + _initDirectory = baseDirectory.empty() ? CPLGetCurrentDir() : baseDirectory; + _datasetFilePath = filePath; + + { // Aquire lock + std::lock_guard lockGuard(_datasetLock); + initialize(); + } +} + +GdalRawTileDataReader::~GdalRawTileDataReader() { + std::lock_guard lockGuard(_datasetLock); + if (_dataset != nullptr) { + GDALClose(_dataset); + _dataset = nullptr; + } +} + +void GdalRawTileDataReader::reset() { + std::lock_guard lockGuard(_datasetLock); + _cached._maxLevel = -1; + if (_dataset != nullptr) { + GDALClose(_dataset); + _dataset = nullptr; + } + initialize(); +} + +int GdalRawTileDataReader::maxChunkLevel() const { + return _cached._maxLevel; +} + +float GdalRawTileDataReader::noDataValueAsFloat() const { + return _gdalDatasetMetaDataCached.noDataValue; +} + +int GdalRawTileDataReader::rasterXSize() const { + return _gdalDatasetMetaDataCached.rasterXSize; +} + +int GdalRawTileDataReader::rasterYSize() const { + return _gdalDatasetMetaDataCached.rasterYSize; +} + +float GdalRawTileDataReader::depthOffset() const { + return _gdalDatasetMetaDataCached.offset; +} + +float GdalRawTileDataReader::depthScale() const { + return _gdalDatasetMetaDataCached.scale; +} + +std::array GdalRawTileDataReader::getGeoTransform() const { + return _gdalDatasetMetaDataCached.padfTransform; +} + +IODescription GdalRawTileDataReader::getIODescription(const TileIndex& tileIndex) const { + IODescription io; + io.read.region = highestResPixelRegion(tileIndex); + + // write region starts in origin + io.write.region.start = PixelRegion::PixelCoordinate(0, 0); + io.write.region.numPixels = PixelRegion::PixelCoordinate( + _initData.dimensionsWithoutPadding().x, _initData.dimensionsWithoutPadding().y); + + io.read.overview = 0; + io.read.fullRegion = fullPixelRegion(); + // For correct sampling in dataset, we need to pad the texture tile + + PixelRegion scaledPadding = padding; + double scale = + io.read.region.numPixels.x / static_cast(io.write.region.numPixels.x); + scaledPadding.numPixels *= scale; + scaledPadding.start *= scale; + + io.read.region.pad(scaledPadding); + io.write.region.pad(padding); + io.write.region.start = PixelRegion::PixelCoordinate(0, 0); + + io.write.bytesPerLine = _initData.bytesPerLine(); + io.write.totalNumBytes = _initData.totalNumBytes(); + + ghoul_assert(io.write.region.numPixels.x == io.write.region.numPixels.y, ""); + ghoul_assert(io.write.region.numPixels.x == _initData.dimensionsWithPadding().x, ""); + + return io; +} + +void GdalRawTileDataReader::initialize() { + if (_datasetFilePath.empty()) { + throw ghoul::RuntimeError("File path must not be empty"); + } + _dataset = openGdalDataset(_datasetFilePath); + + // Assume all raster bands have the same data type + _gdalDatasetMetaDataCached.rasterCount = _dataset->GetRasterCount(); + _gdalDatasetMetaDataCached.scale = _dataset->GetRasterBand(1)->GetScale(); + _gdalDatasetMetaDataCached.offset = _dataset->GetRasterBand(1)->GetOffset(); + _gdalDatasetMetaDataCached.rasterXSize = _dataset->GetRasterXSize(); + _gdalDatasetMetaDataCached.rasterYSize = _dataset->GetRasterYSize(); + _gdalDatasetMetaDataCached.noDataValue = _dataset->GetRasterBand(1)->GetNoDataValue(); + _gdalDatasetMetaDataCached.dataType = tiledatatype::getGdalDataType(_initData.glType()); + + CPLErr err = _dataset->GetGeoTransform(&_gdalDatasetMetaDataCached.padfTransform[0]); + if (err == CE_Failure) { + _gdalDatasetMetaDataCached.padfTransform = RawTileDataReader::getGeoTransform(); + } + + _depthTransform = calculateTileDepthTransform(); + _cached._tileLevelDifference = + calculateTileLevelDifference(_initData.dimensionsWithoutPadding().x); + + int numOverviews = _dataset->GetRasterBand(1)->GetOverviewCount(); + _cached._maxLevel = -_cached._tileLevelDifference; + if (numOverviews > 0) { + _cached._maxLevel += numOverviews - 1; + } + _cached._maxLevel = std::max(_cached._maxLevel, 2); +} + +void GdalRawTileDataReader::readImageData( + IODescription& io, RawTile::ReadError& worstError, char* imageDataDest) const { + + // Only read the minimum number of rasters + int nRastersToRead = std::min(_gdalDatasetMetaDataCached.rasterCount, + static_cast(_initData.nRasters())); + + switch (_initData.ghoulTextureFormat()) { + case ghoul::opengl::Texture::Format::Red: + if (nRastersToRead == 1) { // One channel + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + _initData.bytesPerDatum(); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + break; + case ghoul::opengl::Texture::Format::RG: + case ghoul::opengl::Texture::Format::RGB: + case ghoul::opengl::Texture::Format::RGBA: { + if (nRastersToRead == 1) { // Grayscale + for (int i = 0; i < 3; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + } + else if (nRastersToRead == 2) { // Grayscale + alpha + for (int i = 0; i < 3; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + // Last read is the alpha channel + char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); + RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + else { // Three or more rasters + for (int i = 0; i < nRastersToRead; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(i + 1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + } + break; + } + case ghoul::opengl::Texture::Format::BGR: + case ghoul::opengl::Texture::Format::BGRA: { + if (nRastersToRead == 1) { // Grayscale + for (int i = 0; i < 3; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + } + else if (nRastersToRead == 2) { // Grayscale + alpha + for (int i = 0; i < 3; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(1, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + // Last read is the alpha channel + char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); + RawTile::ReadError err = repeatedRasterRead(2, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + else { // Three or more rasters + for (int i = 0; i < 3 && i < nRastersToRead; i++) { + // The final destination pointer is offsetted by one datum byte size + // for every raster (or data channel, i.e. R in RGB) + char* dataDestination = imageDataDest + (i * _initData.bytesPerDatum()); + + RawTile::ReadError err = repeatedRasterRead(3 - i, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + } + if (nRastersToRead > 3) { // Alpha channel exists + // Last read is the alpha channel + char* dataDestination = imageDataDest + (3 * _initData.bytesPerDatum()); + RawTile::ReadError err = repeatedRasterRead(4, io, dataDestination); + + // CE_None = 0, CE_Debug = 1, CE_Warning = 2, CE_Failure = 3, CE_Fatal = 4 + worstError = std::max(worstError, err); + } + break; + } + default: { + ghoul_assert(false, "Texture format not supported for tiles"); + break; + } + } +} + +RawTile::ReadError GdalRawTileDataReader::rasterRead( + int rasterBand, const IODescription& io, char* dataDestination) const +{ + ghoul_assert(io.read.region.isInside(io.read.fullRegion), "write region of bounds!"); + ghoul_assert( + io.write.region.start.x >= 0 && io.write.region.start.y >= 0, + "Invalid write region" + ); + + PixelRegion::PixelCoordinate end = io.write.region.end(); + size_t largestIndex = + (end.y - 1) * io.write.bytesPerLine + (end.x - 1) * _initData.bytesPerPixel(); + ghoul_assert(largestIndex <= io.write.totalNumBytes, "Invalid write region"); + + char* dataDest = dataDestination; + + // GDAL reads pixels top to bottom, but we want our pixels bottom to top. + // Therefore, we increment the destination pointer to the last line on in the + // buffer, and the we specify in the rasterIO call that we want negative line + // spacing. Doing this compensates the flipped Y axis + dataDest += (io.write.totalNumBytes - io.write.bytesPerLine); + + // handle requested write region. Note -= since flipped y axis + dataDest -= io.write.region.start.y * io.write.bytesPerLine; + dataDest += io.write.region.start.x * _initData.bytesPerPixel(); + + GDALRasterBand* gdalRasterBand = _dataset->GetRasterBand(rasterBand); + CPLErr readError = CE_Failure; + readError = gdalRasterBand->RasterIO( + GF_Read, + io.read.region.start.x, // Begin read x + io.read.region.start.y, // Begin read y + io.read.region.numPixels.x, // width to read x + io.read.region.numPixels.y, // width to read y + dataDest, // Where to put data + io.write.region.numPixels.x, // width to write x in destination + io.write.region.numPixels.y, // width to write y in destination + _gdalDatasetMetaDataCached.dataType, // Type + _initData.bytesPerPixel(), // Pixel spacing + -io.write.bytesPerLine // Line spacing + ); + + // Convert error to RawTile::ReadError + RawTile::ReadError error; + switch (readError) { + case CE_None: error = RawTile::ReadError::None; break; + case CE_Debug: error = RawTile::ReadError::Debug; break; + case CE_Warning: error = RawTile::ReadError::Warning; break; + case CE_Failure: error = RawTile::ReadError::Failure; break; + case CE_Fatal: error = RawTile::ReadError::Fatal; break; + default: error = RawTile::ReadError::Failure; break; + } + return error; +} + +GDALDataset* GdalRawTileDataReader::openGdalDataset(const std::string& filePath) { + GDALDataset* dataset = static_cast( + GDALOpen(filePath.c_str(), GA_ReadOnly)); + if (!dataset) { + using namespace ghoul::filesystem; + std::string correctedPath = FileSystem::ref().pathByAppendingComponent( + _initDirectory, filePath + ); + + dataset = static_cast(GDALOpen(correctedPath.c_str(), GA_ReadOnly)); + if (!dataset) { + throw ghoul::RuntimeError("Failed to load dataset:\n" + filePath); + } + } + return dataset; +} + +int GdalRawTileDataReader::calculateTileLevelDifference(int minimumPixelSize) const { + GDALRasterBand* firstBand = _dataset->GetRasterBand(1); + GDALRasterBand* maxOverview; + int numOverviews = firstBand->GetOverviewCount(); + if (numOverviews <= 0) { // No overviews. Use first band. + maxOverview = firstBand; + } + else { // Pick the highest overview. + maxOverview = firstBand->GetOverview(numOverviews - 1); + } + int sizeLevel0 = maxOverview->GetXSize(); + double diff = log2(minimumPixelSize) - log2(sizeLevel0); + return diff; +} + +} // namespace globebrowsing +} // namespace openspace + +#endif // GLOBEBROWSING_USE_GDAL \ No newline at end of file diff --git a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp index a2f9e000b6..b88fb167ed 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/rawtiledatareader.cpp @@ -330,6 +330,8 @@ std::shared_ptr RawTileDataReader::getTileMetaData( noDataValues[raster] = noDataValueAsFloat(); } + bool allIsMissing = true; + for (int y = 0; y < region.numPixels.y; ++y) { size_t yi = (region.numPixels.y - 1 - y) * bytesPerLine; size_t i = 0; @@ -340,7 +342,9 @@ std::shared_ptr RawTileDataReader::getTileMetaData( _initData.glType(), &(rawTile->imageData[yi + i]) ); - if (val != noDataValue && val == val) { + if (val != noDataValue && + val == val) + { preprocessData->maxValues[raster] = std::max( val, preprocessData->maxValues[raster] @@ -349,14 +353,21 @@ std::shared_ptr RawTileDataReader::getTileMetaData( val, preprocessData->minValues[raster] ); + allIsMissing = false; } else { preprocessData->hasMissingData[raster] = true; + float& floatToRewrite = reinterpret_cast(rawTile->imageData[yi + i]); + floatToRewrite = -FLT_MAX; } i += _initData.bytesPerDatum(); } } } + + if (allIsMissing) { + rawTile->error = RawTile::ReadError::Failure; + } return std::shared_ptr(preprocessData); } diff --git a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp b/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp deleted file mode 100644 index eb2d003bf8..0000000000 --- a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace { - const char* KeyPerformPreProcessing = "PerformPreProcessing"; - const char* KeyTilePixelSize = "TilePixelSize"; - const char* KeyFilePath = "FilePath"; - const char* KeyBasePath = "BasePath"; - const char* KeyPreCacheLevel = "PreCacheLevel"; -} - -namespace openspace { -namespace globebrowsing { -namespace tileprovider { - -CachingTileProvider::CachingTileProvider(const ghoul::Dictionary& dictionary) - : TileProvider(dictionary) -{ - _tileCache = OsEng.moduleEngine().module()->tileCache(); - _name = "Name unspecified"; - dictionary.getValue("Name", _name); - std::string _loggerCat = "CachingTileProvider : " + _name; - - // 1. Get required Keys - std::string filePath; - if (!dictionary.getValue(KeyFilePath, filePath)) { - throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); - } - - layergroupid::ID layerGroupID; - if (!dictionary.getValue("LayerGroupID", layerGroupID)) { - ghoul_assert(false, "Unknown layer group id"); - } - - // 2. Initialize default values for any optional Keys - // getValue does not work for integers - double pixelSize = 0.0; - int tilePixelSize = 0; - if (dictionary.getValue(KeyTilePixelSize, pixelSize)) { - LDEBUG("Default pixel size overridden: " << pixelSize); - tilePixelSize = static_cast(pixelSize); - } - - TileTextureInitData initData(LayerManager::getTileTextureInitData( - layerGroupID, tilePixelSize)); - - bool performPreProcessing = - LayerManager::shouldPerformPreProcessingOnLayergroup(layerGroupID); - if (dictionary.getValue(KeyPerformPreProcessing, performPreProcessing)) { - LDEBUG("Default PerformPreProcessing overridden: " << performPreProcessing); - } - RawTileDataReader::PerformPreprocessing preprocess = - performPreProcessing ? RawTileDataReader::PerformPreprocessing::Yes : - RawTileDataReader::PerformPreprocessing::No; - - std::string basePath; - dictionary.getValue(KeyBasePath, basePath); - - // Initialize instance variables -#ifdef GLOBEBROWSING_USE_GDAL - auto tileDataset = std::make_shared(filePath, initData, - basePath, preprocess); -#else // GLOBEBROWSING_USE_GDAL - auto tileDataset = std::make_shared(filePath, initData, - preprocess); -#endif // GLOBEBROWSING_USE_GDAL - - _asyncTextureDataProvider = std::make_shared(_name, tileDataset); - - if (dictionary.hasKeyAndValue(KeyPreCacheLevel)) { - int preCacheLevel = static_cast(dictionary.value(KeyPreCacheLevel)); - LDEBUG("Precaching '" << filePath << "' with level '" << preCacheLevel << "'"); - for (int level = 0; level <= preCacheLevel; ++level) { - for (int x = 0; x <= level * 2; ++x) { - for (int y = 0; y <= level; ++y) { - _asyncTextureDataProvider->enqueueTileIO({ x, y, level }); - } - } - } - } -} - -CachingTileProvider::CachingTileProvider( - std::shared_ptr tileReader) - : _asyncTextureDataProvider(tileReader) -{ } - -CachingTileProvider::~CachingTileProvider() -{ } - -void CachingTileProvider::update() { - _asyncTextureDataProvider->update(); - initTexturesFromLoadedData(); -} - -void CachingTileProvider::reset() { - _tileCache->clear(); - _asyncTextureDataProvider->reset(); -} - -int CachingTileProvider::maxLevel() { - return _asyncTextureDataProvider->getRawTileDataReader()->maxChunkLevel(); -} - -Tile CachingTileProvider::getTile(const TileIndex& tileIndex) { - if (tileIndex.level > maxLevel()) { - return Tile(nullptr, nullptr, Tile::Status::OutOfRange); - } - - cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - - Tile tile = _tileCache->get(key); - - if (tile.texture() == nullptr) { - _asyncTextureDataProvider->enqueueTileIO(tileIndex); - } - - return tile; -} - -float CachingTileProvider::noDataValueAsFloat() { - return _asyncTextureDataProvider->noDataValueAsFloat(); -} - -void CachingTileProvider::initTexturesFromLoadedData() { - std::shared_ptr rawTile = _asyncTextureDataProvider->popFinishedRawTile(); - if (rawTile) { - cache::ProviderTileKey key = { rawTile->tileIndex, uniqueIdentifier() }; - ghoul_assert(!_tileCache->exist(key), "Tile must not be existing in cache"); - _tileCache->createTileAndPut(key, rawTile); - } -} - -Tile::Status CachingTileProvider::getTileStatus(const TileIndex& tileIndex) { - auto rawTileDataReader = _asyncTextureDataProvider->getRawTileDataReader(); - if (tileIndex.level > rawTileDataReader->maxChunkLevel()) { - return Tile::Status::OutOfRange; - } - - cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; - - return _tileCache->get(key).status(); -} - -TileDepthTransform CachingTileProvider::depthTransform() { - return _asyncTextureDataProvider->getRawTileDataReader()->getDepthTransform(); -} - -} // namespace tileprovider -} // namespace globebrowsing -} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp new file mode 100644 index 0000000000..e763c7e5b7 --- /dev/null +++ b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp @@ -0,0 +1,255 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace { + const char* KeyPerformPreProcessing = "PerformPreProcessing"; + const char* KeyTilePixelSize = "TilePixelSize"; + const char* KeyFilePath = "FilePath"; + const char* KeyBasePath = "BasePath"; + const char* KeyPreCacheLevel = "PreCacheLevel"; +} + +namespace openspace { +namespace globebrowsing { +namespace tileprovider { + +DefaultTileProvider::DefaultTileProvider(const ghoul::Dictionary& dictionary) + : TileProvider(dictionary) + , _filePath("filePath", "File Path", "") + , _tilePixelSize("tilePixelSize", "Tile Pixel Size", 32, 32, 1024) + , _preCacheLevel(0) +{ + _tileCache = OsEng.moduleEngine().module()->tileCache(); + _name = "Name unspecified"; + dictionary.getValue("Name", _name); + std::string _loggerCat = "DefaultTileProvider : " + _name; + + // 1. Get required Keys + std::string filePath; + dictionary.getValue(KeyFilePath, filePath); + //filePath = absPath(filePath); + _filePath.setValue(filePath); + + if (!dictionary.getValue("LayerGroupID", _layerGroupID)) { + ghoul_assert(false, "Unknown layer group id"); + } + + // 2. Initialize default values for any optional Keys + // getValue does not work for integers + double pixelSize = 0.0; + int tilePixelSize = 0; + if (dictionary.getValue(KeyTilePixelSize, pixelSize)) { + LDEBUG("Default pixel size overridden: " << pixelSize); + tilePixelSize = pixelSize; + } + TileTextureInitData initData(LayerManager::getTileTextureInitData( + _layerGroupID, tilePixelSize)); + _tilePixelSize.setValue(initData.dimensionsWithoutPadding().x); + + _performPreProcessing = + LayerManager::shouldPerformPreProcessingOnLayergroup(_layerGroupID); + if (dictionary.getValue(KeyPerformPreProcessing, _performPreProcessing)) { + LDEBUG("Default PerformPreProcessing overridden: " << _performPreProcessing); + } + + if (dictionary.hasKeyAndValue(KeyPreCacheLevel)) { + _preCacheLevel = static_cast(dictionary.value(KeyPreCacheLevel)); + } + + dictionary.getValue(KeyBasePath, _basePath); + + initAsyncTileDataReader(initData); + + // Properties + addProperty(_filePath); + addProperty(_tilePixelSize); +} + +DefaultTileProvider::DefaultTileProvider( + std::shared_ptr tileReader) + : _asyncTextureDataProvider(tileReader) + , _filePath("filePath", "File Path", "") + , _tilePixelSize("tilePixelSize", "Tile Pixel Size", 32, 32, 1024) +{ } + +DefaultTileProvider::~DefaultTileProvider() +{ } + +void DefaultTileProvider::update() { + if (_asyncTextureDataProvider) { + _asyncTextureDataProvider->update(); + initTexturesFromLoadedData(); + if (_asyncTextureDataProvider->shouldBeDeleted()) { + _asyncTextureDataProvider = nullptr; + TileTextureInitData initData(LayerManager::getTileTextureInitData( + _layerGroupID, _tilePixelSize)); + initAsyncTileDataReader(initData); + } + } +} + +void DefaultTileProvider::reset() { + _tileCache->clear(); + if (_asyncTextureDataProvider) { + _asyncTextureDataProvider->prepairToBeDeleted(); + } + else { + TileTextureInitData initData(LayerManager::getTileTextureInitData( + _layerGroupID, _tilePixelSize)); + initAsyncTileDataReader(initData); + } +} + +int DefaultTileProvider::maxLevel() { + if (_asyncTextureDataProvider) { + return _asyncTextureDataProvider->getRawTileDataReader()->maxChunkLevel(); + } + else { + // Current theoretical maximum based on the number of hashes that are possible + // to uniquely identify a tile. See ProviderTileHasher in memoryawaretilecache.h + return 22; + } +} + +Tile DefaultTileProvider::getTile(const TileIndex& tileIndex) { + if (_asyncTextureDataProvider) { + if (tileIndex.level > maxLevel()) { + return Tile(nullptr, nullptr, Tile::Status::OutOfRange); + } + + cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; + + Tile tile = _tileCache->get(key); + + if (tile.texture() == nullptr) { + _asyncTextureDataProvider->enqueueTileIO(tileIndex); + } + + return tile; + } + else { + return Tile(nullptr, nullptr, Tile::Status::Unavailable); + } +} + +float DefaultTileProvider::noDataValueAsFloat() { + if (_asyncTextureDataProvider) { + return _asyncTextureDataProvider->noDataValueAsFloat(); + } + else { + return std::numeric_limits::min(); + } +} + +void DefaultTileProvider::initTexturesFromLoadedData() { + if (_asyncTextureDataProvider) { + std::shared_ptr rawTile = _asyncTextureDataProvider->popFinishedRawTile(); + if (rawTile) { + cache::ProviderTileKey key = { rawTile->tileIndex, uniqueIdentifier() }; + ghoul_assert(!_tileCache->exist(key), "Tile must not be existing in cache"); + _tileCache->createTileAndPut(key, rawTile); + } + } +} + +void DefaultTileProvider::initAsyncTileDataReader(TileTextureInitData initData) { + std::string _loggerCat = "DefaultTileProvider : " + _name; + + RawTileDataReader* tileDataReader = nullptr; + + RawTileDataReader::PerformPreprocessing preprocess = + _performPreProcessing ? RawTileDataReader::PerformPreprocessing::Yes : + RawTileDataReader::PerformPreprocessing::No; + + // Initialize instance variables +#ifdef GLOBEBROWSING_USE_GDAL + auto tileDataset = std::make_shared(_filePath, initData, + _basePath, preprocess); +#else // GLOBEBROWSING_USE_GDAL + auto tileDataset = std::make_shared(_filePath, initData, + preprocess); +#endif // GLOBEBROWSING_USE_GDAL + + _asyncTextureDataProvider = std::make_shared(_name, tileDataset); + + if (_preCacheLevel > -1) { + LDEBUG("Precaching '" << _filePath << "' with level '" << _preCacheLevel << "'"); + for (int level = 0; level <= _preCacheLevel; ++level) { + for (int x = 0; x <= level * 2; ++x) { + for (int y = 0; y <= level; ++y) { + _asyncTextureDataProvider->enqueueTileIO({ x, y, level }); + } + } + } + } +} + +Tile::Status DefaultTileProvider::getTileStatus(const TileIndex& tileIndex) { + if (_asyncTextureDataProvider) { + auto rawTileDataReader = _asyncTextureDataProvider->getRawTileDataReader(); + if (tileIndex.level > rawTileDataReader->maxChunkLevel()) { + return Tile::Status::OutOfRange; + } + + cache::ProviderTileKey key = { tileIndex, uniqueIdentifier() }; + + return _tileCache->get(key).status(); + } + else { + return Tile::Status::Unavailable; + } +} + +TileDepthTransform DefaultTileProvider::depthTransform() { + if (_asyncTextureDataProvider) { + return _asyncTextureDataProvider->getRawTileDataReader()->getDepthTransform(); + } + else { + return { 1.0f, 0.0f }; + } +} + +} // namespace tileprovider +} // namespace globebrowsing +} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.h similarity index 86% rename from modules/globebrowsing/tile/tileprovider/cachingtileprovider.h rename to modules/globebrowsing/tile/tileprovider/defaulttileprovider.h index 6fd5c0fa03..bf2928dd37 100644 --- a/modules/globebrowsing/tile/tileprovider/cachingtileprovider.h +++ b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.h @@ -28,6 +28,9 @@ #include #include +#include +#include + namespace openspace { class PixelBuffer; @@ -43,12 +46,12 @@ namespace tileprovider { * Provides tiles loaded by AsyncTileDataProvider and * caches them in memory using LRU caching */ -class CachingTileProvider : public TileProvider { +class DefaultTileProvider : public TileProvider { public: - CachingTileProvider(const ghoul::Dictionary& dictionary); - CachingTileProvider(std::shared_ptr tileReader); + DefaultTileProvider(const ghoul::Dictionary& dictionary); + DefaultTileProvider(std::shared_ptr tileReader); - virtual ~CachingTileProvider() override; + virtual ~DefaultTileProvider() override; /** * \returns a Tile with status OK iff it exists in in-memory @@ -73,9 +76,18 @@ private: */ void initTexturesFromLoadedData(); + void initAsyncTileDataReader(TileTextureInitData initData); + std::shared_ptr _asyncTextureDataProvider; cache::MemoryAwareTileCache* _tileCache; + + properties::StringProperty _filePath; + properties::IntProperty _tilePixelSize; + layergroupid::GroupID _layerGroupID; + std::string _basePath; + int _preCacheLevel; + bool _performPreProcessing; }; } // namespace tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp index 8c16349993..0cca078164 100644 --- a/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/presentationslideprovider.cpp @@ -22,6 +22,8 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ +#if 0 + #include #include #include @@ -112,3 +114,5 @@ TileProvider* PresentationSlideProvider::slideProvider() { } // namespace tileprovider } // namespace globebrowsing } // namespace openspace + +#endif diff --git a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp b/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp deleted file mode 100644 index 944c4594ed..0000000000 --- a/modules/globebrowsing/tile/tileprovider/projectiontileprovider.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -namespace { - const char* _loggerCat = "ProjectionTileProvider"; - - const char* keyGeometry = "Geometry"; - const char* keyProjection = "Projection"; - const char* keyMeridianShift = "Textures.MeridianShift"; - const char* keyColorTexture = "Textures.Color"; - const char* keyHeightTexture = "Textures.Height"; - - const char* keyRadius = "Geometry.Radius"; - const char* keyShading = "PerformShading"; - const char* _mainFrame = "GALACTIC"; -} - -namespace openspace { -namespace globebrowsing { -namespace tileprovider { - -/* -documentation::Documentation ProjectionTileProvider::Documentation() { - using namespace openspace::documentation; - return { - "Renderable Planet Projection", - "newhorizons_renderable_planetprojection", - { - { - "Type", - new StringEqualVerifier("RenderablePlanetProjection"), - "", - Optional::No - }, - { - keyGeometry, - new ReferencingVerifier("space_geometry_planet"), - "The geometry that is used for rendering this planet.", - Optional::No - }, - { - keyProjection, - new ReferencingVerifier("newhorizons_projectioncomponent"), - "Contains information about projecting onto this planet.", - Optional::No - }, - { - keyMeridianShift, - new BoolVerifier, - "Determines whether the meridian of the planet should be shifted by 180 " - "degrees. The default value is 'false'", - Optional::Yes - }, - { - keyColorTexture, - new StringVerifier, - "The path to the base color texture that is used on the planet prior to " - "any image projection. The path can use tokens of the form '${...}' or " - "be specified relative to the directory of the mod file.", - Optional::No - }, - { - keyHeightTexture, - new StringVerifier, - "The path to the height map texture that is used on the planet. The path " - "can use tokens of the form '${...}' or be specified relative to the " - "directory of the mod file. If no height map is specified the planet " - "does not use a height field.", - Optional::Yes - } - } - }; -} -*/ - -ProjectionTileProvider::ProjectionTileProvider(const ghoul::Dictionary& dictionary) - : _fboProgramObject(nullptr) - , _capture(false) - , _defaultTile(Tile::TileUnavailable) -{ - - ghoul::Dictionary geometryDictionary; - bool success = dictionary.getValue( - keyGeometry, geometryDictionary); - if (success) { - geometryDictionary.setValue(SceneGraphNode::KeyName, "TestGeometry"); - using planetgeometry::PlanetGeometry; - _geometry = std::unique_ptr( - PlanetGeometry::createFromDictionary(geometryDictionary) - ); - } - - _projectionComponent.initialize(dictionary.value(keyProjection)); - - - addPropertySubOwner(_geometry.get()); - addPropertySubOwner(_projectionComponent); -} - -ProjectionTileProvider::~ProjectionTileProvider(){ - -} - -bool ProjectionTileProvider::initialize() { - bool completeSuccess = true; - completeSuccess &= TileProvider::initialize(); - - _fboProgramObject = ghoul::opengl::ProgramObject::Build("fboPassProgram", - "${MODULE_NEWHORIZONS}/shaders/renderablePlanetProjection_vs.glsl", - "${MODULE_NEWHORIZONS}/shaders/renderablePlanetProjection_fs.glsl" - ); - - completeSuccess &= _projectionComponent.initializeGL(); - completeSuccess &= _geometry->initialize(nullptr); - - if (completeSuccess) { - //completeSuccess &= auxiliaryRendertarget(); - // SCREEN-QUAD - const GLfloat size = 1.f; - const GLfloat w = 1.f; - const GLfloat vertex_data[] = { - -size, -size, 0.f, w, 0.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - -size, size, 0.f, w, 0.f, 1.f, - -size, -size, 0.f, w, 0.f, 0.f, - size, -size, 0.f, w, 1.f, 0.f, - size, size, 0.f, w, 1.f, 1.f, - }; - - glGenVertexArrays(1, &_quad); - glBindVertexArray(_quad); - glGenBuffers(1, &_vertexPositionBuffer); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(0)); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, reinterpret_cast(sizeof(GLfloat) * 4)); - - glBindVertexArray(0); - } - - return completeSuccess; -} - -bool ProjectionTileProvider::deinitialize() { - _projectionComponent.deinitialize(); - _geometry = nullptr; - - glDeleteVertexArrays(1, &_quad); - glDeleteBuffers(1, &_vertexPositionBuffer); - - _fboProgramObject = nullptr; - - return true; -} - -void ProjectionTileProvider::update() { - // Update - if (_fboProgramObject->isDirty()) { - _fboProgramObject->rebuildFromFile(); - } - - _projectionComponent.update(); - - _time = Time::ref().j2000Seconds(); - _capture = false; - - if (openspace::ImageSequencer::ref().isReady()){ - openspace::ImageSequencer::ref().updateSequencer(_time); - if (_projectionComponent.doesPerformProjection()) { - _capture = openspace::ImageSequencer::ref().getImagePaths( - _imageTimes, - _projectionComponent.projecteeId(), - _projectionComponent.instrumentId() - ); - } - } - - _stateMatrix = glm::dmat3(1.0); - - - - - - - - - - - - - - - // Projection - - if (_projectionComponent.needsClearProjection()) - _projectionComponent.clearAllProjections(); - - _camScaling = glm::vec2(1.0);// data.camera.scaling(); - _up = glm::vec3(0,1,0);// data.camera.lookUpVectorCameraSpace(); - - if (_capture && _projectionComponent.doesPerformProjection()) { - for (const Image& img : _imageTimes) { - attitudeParameters(img.timeRange.start); - imageProjectGPU(_projectionComponent.loadProjectionTexture(img.path)); - } - _capture = false; - } - attitudeParameters(_time); - _imageTimes.clear(); - -} - -void ProjectionTileProvider::reset() { -} - -int ProjectionTileProvider::maxLevel() { - return 3; -} - -Tile ProjectionTileProvider::getTile(const TileIndex& tileIndex) { - _projectionComponent.projectionTexture(); -} - -float ProjectionTileProvider::noDataValueAsFloat() { - -} - -Tile ProjectionTileProvider::getDefaultTile() { - -} - -Tile::Status ProjectionTileProvider::getTileStatus(const TileIndex& tileIndex) { - return Tile::Status::OK; -} - -TileDepthTransform ProjectionTileProvider::depthTransform() { - -} - -void ProjectionTileProvider::attitudeParameters(double time) { - // precomputations for shader - _instrumentMatrix = SpiceManager::ref().positionTransformMatrix( - _projectionComponent.instrumentId(), _mainFrame, time - ); - - _transform = glm::mat4(1); - //90 deg rotation w.r.t spice req. - glm::mat4 rot = glm::rotate( - _transform, - static_cast(M_PI_2), - glm::vec3(1, 0, 0) - ); - glm::mat4 roty = glm::rotate( - _transform, - static_cast(M_PI_2), - glm::vec3(0, -1, 0) - ); - - _transform = glm::mat4(_stateMatrix); - - glm::dvec3 bs; - try { - SpiceManager::FieldOfViewResult res = SpiceManager::ref().fieldOfView(_projectionComponent.instrumentId()); - bs = std::move(res.boresightVector); - } - catch (const SpiceManager::SpiceException& e) { - LERRORC(e.component, e.what()); - return; - } - - double lightTime; - glm::dvec3 p = SpiceManager::ref().targetPosition( - _projectionComponent.projectorId(), - _projectionComponent.projecteeId(), - _mainFrame, - _projectionComponent.aberration(), - time, - lightTime - ); - psc position = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); - - //change to KM and add psc camera scaling. - position[3] += (3 + _camScaling[1]); - //position[3] += 3; - glm::vec3 cpos = position.vec3(); - - float distance = glm::length(cpos); - float radius = 1185000.0f; - - _projectorMatrix = _projectionComponent.computeProjectorMatrix( - cpos, - bs, - _up, - _instrumentMatrix, - _projectionComponent.fieldOfViewY(), - _projectionComponent.aspectRatio(), - distance - radius, - distance + radius, - _boresight - ); -} - -void ProjectionTileProvider::imageProjectGPU( - std::shared_ptr projectionTexture) -{ - _projectionComponent.imageProjectBegin(); - - _fboProgramObject->activate(); - - ghoul::opengl::TextureUnit unitFbo; - unitFbo.activate(); - projectionTexture->bind(); - _fboProgramObject->setUniform("projectionTexture", unitFbo); - - _fboProgramObject->setUniform("ProjectorMatrix", _projectorMatrix); - _fboProgramObject->setUniform("ModelTransform" , _transform); - _fboProgramObject->setUniform("_scaling" , _camScaling); - _fboProgramObject->setUniform("boresight" , _boresight); - - if (_geometry->hasProperty("radius")){ - ghoul::any r = _geometry->property("radius")->get(); - if (glm::vec4* radius = ghoul::any_cast(&r)){ - _fboProgramObject->setUniform("_radius", radius); - } - }else{ - LERROR("Geometry object needs to provide radius"); - } - if (_geometry->hasProperty("segments")){ - ghoul::any s = _geometry->property("segments")->get(); - if (int* segments = ghoul::any_cast(&s)){ - _fboProgramObject->setUniform("_segments", segments[0]); - } - }else{ - LERROR("Geometry object needs to provide segment count"); - } - - glBindVertexArray(_quad); - glDrawArrays(GL_TRIANGLES, 0, 6); - _fboProgramObject->deactivate(); - - _projectionComponent.imageProjectEnd(); -} - - -} // namespace tileprovider -} // namespace globebrowsing -} // namespace openspace diff --git a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp b/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp index 413784a698..38efce4ba6 100644 --- a/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/singleimageprovider.cpp @@ -38,18 +38,21 @@ namespace tileprovider { SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) : _tile(nullptr, nullptr, Tile::Status::Unavailable) + , _filePath("filePath", "File Path", "") { // Required input - if (!dictionary.getValue(KeyFilePath, _imagePath)) { - throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); - } + std::string filePath; + dictionary.getValue(KeyFilePath, filePath); + _filePath.setValue(filePath); + + addProperty(_filePath); reset(); } SingleImageProvider::SingleImageProvider(const std::string& imagePath) - : _imagePath(imagePath) - , _tile(nullptr, nullptr, Tile::Status::Unavailable) + : _tile(nullptr, nullptr, Tile::Status::Unavailable) + , _filePath("filePath", "File Path", imagePath) { reset(); } @@ -74,12 +77,15 @@ void SingleImageProvider::update() { } void SingleImageProvider::reset() { - _tileTexture = ghoul::io::TextureReader::ref().loadTexture(_imagePath); + if (_filePath.value().empty()) { + return; + } + _tileTexture = ghoul::io::TextureReader::ref().loadTexture(_filePath); Tile::Status tileStatus = _tileTexture ? Tile::Status::OK : Tile::Status::IOError; if (!_tileTexture) { throw std::runtime_error(std::string("Unable to load texture '") - + _imagePath + "'"); + + _filePath.value() + "'"); } _tileTexture->uploadTexture(); diff --git a/modules/globebrowsing/tile/tileprovider/singleimageprovider.h b/modules/globebrowsing/tile/tileprovider/singleimageprovider.h index e4f0ac7f34..d15aaa77f7 100644 --- a/modules/globebrowsing/tile/tileprovider/singleimageprovider.h +++ b/modules/globebrowsing/tile/tileprovider/singleimageprovider.h @@ -27,6 +27,8 @@ #include +#include + namespace openspace { namespace globebrowsing { namespace tileprovider { @@ -46,8 +48,9 @@ public: private: std::unique_ptr _tileTexture; - std::string _imagePath; Tile _tile; + + properties::StringProperty _filePath; }; } // namespace tileprovider diff --git a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp index 042d06c9cb..fb12db848a 100644 --- a/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/sizereferencetileprovider.cpp @@ -47,7 +47,7 @@ namespace { } SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) - : TextTileProvider(LayerManager::getTileTextureInitData(layergroupid::ID::ColorLayers)) + : TextTileProvider(LayerManager::getTileTextureInitData(layergroupid::GroupID::ColorLayers)) , _backgroundTile(Tile::TileUnavailable) { @@ -55,9 +55,7 @@ SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& di _font = OsEng.fontManager().font("Mono", _fontSize); glm::dvec3 radii(1,1,1); - if (!dictionary.getValue(KeyRadii, radii)) { - throw std::runtime_error("Must define key '" + std::string(KeyRadii) + "'"); - } + dictionary.getValue(KeyRadii, radii); _ellipsoid = Ellipsoid(radii); } diff --git a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp index e7a622e5ac..1c3666e0eb 100644 --- a/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/temporaltileprovider.cpp @@ -26,7 +26,7 @@ #include -#include +#include #include #include @@ -57,47 +57,73 @@ const char* TemporalTileProvider::TemporalXMLTags::TIME_RESOLUTION = const char* TemporalTileProvider::TemporalXMLTags::TIME_FORMAT = "OpenSpaceTimeIdFormat"; TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary) - : _initDict(dictionary) + : _initDict(dictionary) + , _filePath("filePath", "File Path", "") + , _successfulInitialization(false) { - if (!dictionary.getValue(KeyFilePath, _datasetFile)) { - throw std::runtime_error(std::string("Must define key '") + KeyFilePath + "'"); + std::string filePath; + dictionary.getValue(KeyFilePath, filePath); + try { + filePath = absPath(filePath); + } + catch (const std::runtime_error& e) { + // File path was not a path to a file but a GDAL config or empty + } + + _filePath.setValue(filePath); + addProperty(_filePath); + + if (readFilePath()) { + const bool hasStart = dictionary.hasKeyAndValue(KeyPreCacheStartTime); + const bool hasEnd = dictionary.hasKeyAndValue(KeyPreCacheEndTime); + if (hasStart && hasEnd) { + const std::string start = dictionary.value(KeyPreCacheStartTime); + const std::string end = dictionary.value(KeyPreCacheEndTime); + std::vector

The TuioClient class is the central TUIO protocol decoder component. It provides a simple callback infrastructure using the {@link TuioListener} interface. - * In order to receive and decode TUIO messages an instance of TuioClient needs to be created. The TuioClient instance then generates TUIO events - * which are broadcasted to all registered classes that implement the {@link TuioListener} interface.

- *

- * TuioClient *client = new TuioClient();
- * client->addTuioListener(myTuioListener);
- * client->connect();
- *

- * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioClient : public TuioDispatcher { - - public: - /** - * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the default UDP port 3333 - * - */ - TuioClient(); - - /** - * This constructor creates a TuioClient that uses an internal UdpReceiver listening to the provided UDP port - * - * @param port the UDP port the internal UdpReceiver is listening to - */ - TuioClient(int port); - - /** - * This constructor creates a TuioClient that uses the provided OscReceiver for the incoming OSC data - * - * @param oscreceiver the OscReceiver implementation for the chosen transport method (UDP, TCP ...) - */ - TuioClient(OscReceiver *oscreceiver); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioClient(); - - /** - * The TuioClient connects and starts receiving TUIO messages from its associated OscReceiver - * - * @param lock running in the background if set to false (default) - */ - void connect(bool lock=false); - - /** - * The TuioClient disconnects and stops receiving TUIO messages from its associated OscReceiver - */ - void disconnect(); - - /** - * Returns true if this TuioClient is currently connected. - * @return true if this TuioClient is currently connected - */ - bool isConnected(); - - /** - * Returns a List of all currently active TuioObjects - * - * @return a List of TuioObjects - */ - std::list getTuioObjects() { - return TuioDispatcher::getTuioObjects(); - } - - /** - * Returns a List of all currently active TuioObjects - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioObjects - */ - std::list getTuioObjects(int source_id); - - /** - * Returns a List with a copy of all currently active TuioObjects - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List with a copy of TuioObjects - */ - std::list copyTuioObjects(int source_id); - - - /** - * Returns a List with a copy of all currently active TuioObjects - * - * @return a List with a copy of TuioObjects - */ - std::list copyTuioObjects() { - return TuioDispatcher::copyTuioObjects(); - } - - /** - * Returns the TuioObject corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioObject - * - * @param s_id the session ID of the corresponding TuioObject - * @return an active TuioObject corresponding to the provided Session ID or NULL - */ - TuioObject* getTuioObject(long s_id) { - return getTuioObject(0,s_id); - }; - - /** - * Returns the TuioObject corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioObject - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioObject - * @return an active TuioObject corresponding to the provided Session ID or NULL - */ - TuioObject* getTuioObject(int src_id, long s_id); - - /** - * Returns a List of all currently active TuioCursors - * - * @return a List of TuioCursors - */ - std::list getTuioCursors() { - return TuioDispatcher::getTuioCursors(); - } - - /** - * Returns a List of all currently active TuioCursors - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioCursors - */ - std::list getTuioCursors(int source_id); - - /** - * Returns a List with a copy of all currently active TuioCursors - * - * @return a List with a copy of TuioCursors - */ - std::list copyTuioCursors() { - return TuioDispatcher::copyTuioCursors(); - } - - /** - * Returns a List with a copy of all currently active TuioCursors - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List with a copy of TuioCursors - */ - std::list copyTuioCursors(int source_id); - - /** - * Returns the TuioCursor corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioCursor - * - * @param s_id the session ID of the corresponding TuioCursor - * @return an active TuioCursor corresponding to the provided Session ID or NULL - */ - TuioCursor* getTuioCursor(long s_id) { - return getTuioCursor(0,s_id); - }; - - /** - * Returns the TuioCursor corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioCursor - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioCursor - * @return an active TuioCursor corresponding to the provided Session ID or NULL - */ - TuioCursor* getTuioCursor(int src_id, long s_id); - - /** - * Returns a List of all currently active TuioBlobs - * - * @return a List of TuioBlobs - */ - std::list getTuioBlobs() { - return TuioDispatcher::getTuioBlobs(); - } - - /** - * Returns a List of all currently active TuioBlobs - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List of TuioBlobs - */ - std::list getTuioBlobs(int source_id); - - /** - * Returns a List with a copy of all currently active TuioBlobs - * - * @return a List with a copy of TuioBlobs - */ - std::list copyTuioBlobs() { - return TuioDispatcher::copyTuioBlobs(); - } - - /** - * Returns a List with a copy of all currently active TuioBlobs - * which are associated to the given Source ID - * - * @param src_id the source ID of the corresponding TUIO source - * @return a List with a copy of TuioBlobs - */ - std::list copyTuioBlobs(int source_id); - - /** - * Returns the TuioBlob corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioBlob - * - * @param s_id the session ID of the corresponding TuioBlob - * @return an active TuioBlob corresponding to the provided Session ID or NULL - */ - TuioBlob* getTuioBlob(long s_id) { - return getTuioBlob(0,s_id); - }; - - /** - * Returns the TuioBlob corresponding to the provided Session ID - * which is associated to the given Source ID - * or NULL if the Session ID does not refer to an active TuioBlob - * - * @param src_id the source ID of the corresponding TUIO source - * @param s_id the session ID of the corresponding TuioBlob - * @return an active TuioBlob corresponding to the provided Session ID or NULL - */ - TuioBlob* getTuioBlob(int src_id, long s_id); - - void processOSC( const osc::ReceivedMessage& message); - - private: - void initialize(); - - std::list frameObjects; - std::list aliveObjectList; - std::list frameCursors; - std::list aliveCursorList; - std::list frameBlobs; - std::list aliveBlobList; - - osc::int32 currentFrame; - TuioTime currentTime; - - std::list freeCursorList, freeCursorBuffer; - std::map maxCursorID; - - std::list freeBlobList, freeBlobBuffer; - std::map maxBlobID; - - std::map sourceList; - int source_id; - char *source_name; - char *source_addr; - - OscReceiver *receiver; - bool local_receiver; - }; -}; -#endif /* INCLUDED_TUIOCLIENT_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioContainer.cpp b/modules/touch/ext/libTUIO/TUIO/TuioContainer.cpp deleted file mode 100644 index ba85fb6456..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioContainer.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioContainer.h" -using namespace TUIO; - -TuioContainer::TuioContainer (TuioTime ttime, long si, float xp, float yp):TuioPoint(ttime, xp,yp) -,state(TUIO_ADDED) -,source_id(0) -,source_name("undefined") -,source_addr("localhost") -{ - session_id = si; - x_speed = 0.0f; - y_speed = 0.0f; - motion_speed = 0.0f; - motion_accel = 0.0f; - x_accel = 0.0f; - y_accel = 0.0f; - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - lastPoint = &path.back(); -} - -TuioContainer::TuioContainer (long si, float xp, float yp):TuioPoint(xp,yp) -,state(TUIO_ADDED) -,source_id(0) -,source_name("undefined") -,source_addr("localhost") -{ - session_id = si; - x_speed = 0.0f; - y_speed = 0.0f; - motion_speed = 0.0f; - motion_accel = 0.0f; - x_accel = 0.0f; - y_accel = 0.0f; - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - lastPoint = &path.back(); -} - -TuioContainer::TuioContainer (TuioContainer *tcon):TuioPoint(tcon) -,state(TUIO_ADDED) -,source_id(0) -,source_name("undefined") -,source_addr("localhost") -{ - session_id = tcon->getSessionID(); - x_speed = 0.0f; - y_speed = 0.0f; - motion_speed = 0.0f; - motion_accel = 0.0f; - x_accel = 0.0f; - y_accel = 0.0f; - - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - lastPoint = &path.back(); -} - -void TuioContainer::setTuioSource(int src_id, const char *src_name, const char *src_addr) { - source_id = src_id; - source_name = std::string(src_name); - source_addr = std::string(src_addr); -} - -const char* TuioContainer::getTuioSourceName() const{ - return source_name.c_str(); -} - -const char* TuioContainer::getTuioSourceAddress() const{ - return source_addr.c_str(); -} - -int TuioContainer::getTuioSourceID() const{ - return source_id; -} - -void TuioContainer::update (TuioTime ttime, float xp, float yp) { - lastPoint = &path.back(); - TuioPoint::update(ttime,xp, yp); - - TuioTime diffTime = currentTime - lastPoint->getTuioTime(); - float dt = diffTime.getTotalMilliseconds()/1000.0f; - float dx = xpos - lastPoint->getX(); - float dy = ypos - lastPoint->getY(); - float dist = sqrt(dx*dx+dy*dy); - float last_motion_speed = motion_speed; - float last_x_speed = x_speed; - float last_y_speed = y_speed; - - x_speed = dx/dt; - y_speed = dy/dt; - motion_speed = dist/dt; - motion_accel = (motion_speed - last_motion_speed)/dt; - x_accel = (x_speed - last_x_speed)/dt; - y_accel = (y_speed - last_y_speed)/dt; - - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else state = TUIO_STOPPED; -} - -void TuioContainer::stop(TuioTime ttime) { - if ( state==TUIO_IDLE )update(ttime,xpos,ypos); - else state=TUIO_IDLE; -} - -void TuioContainer::update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma) { - TuioPoint::update(ttime,xp, yp); - x_speed = xs; - y_speed = ys; - motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); - motion_accel = ma; - x_accel = ma; - y_accel = ma; - - lastPoint = &path.back(); - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else state = TUIO_STOPPED; -} - -void TuioContainer::update (float xp, float yp, float xs, float ys, float ma) { - TuioPoint::update(xp,yp); - x_speed = xs; - y_speed = ys; - motion_speed = (float)sqrt(x_speed*x_speed+y_speed*y_speed); - motion_accel = ma; - x_accel = ma; - y_accel = ma; - - lastPoint = &path.back(); - TuioPoint p(currentTime,xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else state = TUIO_STOPPED; -} - -void TuioContainer::update (TuioContainer *tcon) { - TuioPoint::update(tcon); - x_speed = tcon->getXSpeed(); - y_speed = tcon->getYSpeed(); - motion_speed = tcon->getMotionSpeed(); - motion_accel = tcon->getMotionAccel(); - x_accel = motion_accel; - y_accel = motion_accel; - - lastPoint = &path.back(); - TuioPoint p(tcon->getTuioTime(),xpos,ypos); - path.push_back(p); - if (path.size()>MAX_PATH_SIZE) path.pop_front(); - - if (motion_accel>0) state = TUIO_ACCELERATING; - else if (motion_accel<0) state = TUIO_DECELERATING; - else state = TUIO_STOPPED; -} - -void TuioContainer::remove(TuioTime ttime) { - currentTime = ttime; - state = TUIO_REMOVED; -} - -long TuioContainer::getSessionID() const{ - return session_id; -} - -void TuioContainer::setSessionID(long s_id) { - session_id = s_id; -} - -float TuioContainer::getXSpeed() const{ - return x_speed; -} - -float TuioContainer::getYSpeed() const{ - return y_speed; -} - -TuioPoint TuioContainer::getPosition() const{ - TuioPoint p(xpos,ypos); - return p; -} - -std::list TuioContainer::getPath() const{ - return path; -} - -float TuioContainer::getMotionSpeed() const{ - return motion_speed; -} - -float TuioContainer::getMotionAccel() const{ - return motion_accel; -} - -int TuioContainer::getTuioState() const{ - return state; -} - -bool TuioContainer::isMoving() const{ - if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING)) return true; - else return false; -} - -TuioPoint TuioContainer::predictPosition() { - /*if (path.size()>1) { - std::list::iterator iter = path.end(); - std::advance(iter, -2); - - TuioTime diffTime = currentTime - (*iter).getTuioTime(); - float dt = diffTime.getTotalMilliseconds()/1000.0f; - - float tx = x_speed * dt; - float ty = y_speed * dt; - - float nx = xpos+tx-tx*x_accel*dt; - float ny = ypos+ty-ty*y_accel*dt; - - //if (xposFilter && yposFilter) { - // nx = xposFilter->filter(nx,dt); - // ny = yposFilter->filter(ny,dt); - // //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; - //} - - //std::cout << nx << " " << ny << std::endl; - return TuioPoint(nx,ny); - } else return TuioPoint(xpos,ypos);*/ - - TuioTime diffTime = currentTime - lastPoint->getTuioTime(); - float dt = diffTime.getTotalMilliseconds()/1000.0f; - - float tx = x_speed * dt; - float ty = y_speed * dt; - - float nx = xpos+tx-tx*x_accel*dt; - float ny = ypos+ty-ty*y_accel*dt; - - //if (xposFilter && yposFilter) { - // nx = xposFilter->filter(nx,dt); - // ny = yposFilter->filter(ny,dt); - // //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; - //} - - //std::cout << nx << " " << ny << std::endl; - return TuioPoint(nx,ny); - - -} - diff --git a/modules/touch/ext/libTUIO/TUIO/TuioContainer.h b/modules/touch/ext/libTUIO/TUIO/TuioContainer.h deleted file mode 100644 index c25a0b21a8..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioContainer.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOCONTAINER_H -#define INCLUDED_TUIOCONTAINER_H - -#include "TuioPoint.h" -#include -#include - -#define TUIO_IDLE 0 -#define TUIO_ADDED 1 -#define TUIO_ACCELERATING 2 -#define TUIO_DECELERATING 3 -#define TUIO_ROTATING 4 -#define TUIO_STOPPED 5 -#define TUIO_REMOVED 6 - -#define MAX_PATH_SIZE 128 - -namespace TUIO { - - /** - * The abstract TuioContainer class defines common attributes that apply to both subclasses {@link TuioObject} and {@link TuioCursor}. - * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioContainer: public TuioPoint { - - - private: - - TuioPoint *lastPoint; - - protected: - /** - * The unique session ID number that is assigned to each TUIO object or cursor. - */ - long session_id; - /** - * The X-axis velocity value. - */ - float x_speed; - /** - * The Y-axis velocity value. - */ - float y_speed; - /** - * The motion speed value. - */ - float motion_speed; - /** - * The motion acceleration value. - */ - float motion_accel; - float x_accel; - float y_accel; - /** - * A List of TuioPoints containing all the previous positions of the TUIO component. - */ - std::list path; - /** - * Reflects the current state of the TuioComponent - */ - int state; - /** - * The ID of the TUIO source - */ - int source_id; - /** - * The name of the TUIO source - */ - std::string source_name; - /** - * The address of the TUIO source - */ - std::string source_addr; - - public: - using TuioPoint::update; - - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, X and Y coordinate to the newly created TuioContainer. - * - * @param ttime the TuioTime to assign - * @param si the Session ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - TuioContainer (TuioTime ttime, long si, float xp, float yp); - - /** - * This constructor takes the provided Session ID, X and Y coordinate - * and assigs these values to the newly created TuioContainer. - * - * @param si the Session ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - TuioContainer (long si, float xp, float yp); - - /** - * This constructor takes the atttibutes of the provided TuioContainer - * and assigs these values to the newly created TuioContainer. - * - * @param tcon the TuioContainer to assign - */ - TuioContainer (TuioContainer *tcon); - - /** - * The destructor is doing nothing in particular. - */ - virtual ~TuioContainer(){}; - - /** - * Sets the ID, name and address of the TUIO source - * - * @param src_id the ID of the TUIO source - * @param src_name the name of the TUIO source - * @param src_addr the address of the TUIO source - */ - virtual void setTuioSource(int src_id, const char *src_name, const char *src_addr); - - /** - * Returns the name of the TUIO source - */ - virtual const char* getTuioSourceName() const; - - /** - * Returns the address of the TUIO source - */ - virtual const char* getTuioSourceAddress() const; - - /** - * Returns the ID of the TUIO source - */ - virtual int getTuioSourceID() const; - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate to the private TuioContainer attributes. - * The speed and accleration values are calculated accordingly. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - virtual void update (TuioTime ttime, float xp, float yp); - - /** - * This method is used to calculate the speed and acceleration values of - * TuioContainers with unchanged positions. - */ - virtual void stop(TuioTime ttime); - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate, X and Y velocity and acceleration - * to the private TuioContainer attributes. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param ma the acceleration to assign - */ - virtual void update (TuioTime ttime, float xp, float yp, float xs, float ys, float ma); - - /** - * Assigns the provided X and Y coordinate, X and Y velocity and acceleration - * to the private TuioContainer attributes. The TuioTime time stamp remains unchanged. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param ma the acceleration to assign - */ - virtual void update (float xp, float yp, float xs, float ys, float ma); - - /** - * Takes the atttibutes of the provided TuioContainer - * and assigs these values to this TuioContainer. - * The TuioTime time stamp of this TuioContainer remains unchanged. - * - * @param tcon the TuioContainer to assign - */ - virtual void update (TuioContainer *tcon); - - /** - * Assigns the REMOVE state to this TuioContainer and sets - * its TuioTime time stamp to the provided TuioTime argument. - * - * @param ttime the TuioTime to assign - */ - virtual void remove(TuioTime ttime); - - /** - * Returns the Session ID of this TuioContainer. - * @return the Session ID of this TuioContainer - */ - virtual long getSessionID() const; - - /** - * Sets the Session ID of this TuioContainer. - * @param s_id the new Session ID for this TuioContainer - */ - virtual void setSessionID(long s_id); - - /** - * Returns the X velocity of this TuioContainer. - * @return the X velocity of this TuioContainer - */ - virtual float getXSpeed() const; - - /** - * Returns the Y velocity of this TuioContainer. - * @return the Y velocity of this TuioContainer - */ - virtual float getYSpeed() const; - - /** - * Returns the position of this TuioContainer. - * @return the position of this TuioContainer - */ - virtual TuioPoint getPosition() const; - - /** - * Returns the path of this TuioContainer. - * @return the path of this TuioContainer - */ - virtual std::list getPath() const; - - /** - * Returns the motion speed of this TuioContainer. - * @return the motion speed of this TuioContainer - */ - virtual float getMotionSpeed() const; - - /** - * Returns the motion acceleration of this TuioContainer. - * @return the motion acceleration of this TuioContainer - */ - virtual float getMotionAccel() const; - - /** - * Returns the TUIO state of this TuioContainer. - * @return the TUIO state of this TuioContainer - */ - virtual int getTuioState() const; - - /** - * Returns true of this TuioContainer is moving. - * @return true of this TuioContainer is moving - */ - virtual bool isMoving() const; - - virtual TuioPoint predictPosition(); - }; -} -#endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp b/modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp deleted file mode 100644 index 4df31cd345..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioCursor.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioCursor.h" - -using namespace TUIO; - -TuioCursor::TuioCursor (TuioTime ttime, long si, int ci, float xp, float yp):TuioContainer(ttime,si,xp,yp) { - cursor_id = ci; -} - -TuioCursor::TuioCursor (long si, int ci, float xp, float yp):TuioContainer(si,xp,yp) { - cursor_id = ci; -} - -TuioCursor::TuioCursor (TuioCursor *tcur):TuioContainer(tcur) { - cursor_id = tcur->getCursorID(); -} - -int TuioCursor::getCursorID() const{ - return cursor_id; -}; - diff --git a/modules/touch/ext/libTUIO/TUIO/TuioCursor.h b/modules/touch/ext/libTUIO/TUIO/TuioCursor.h deleted file mode 100644 index 74c0e59d70..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioCursor.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOCURSOR_H -#define INCLUDED_TUIOCURSOR_H - -#include "TuioContainer.h" - -namespace TUIO { - - /** - * The TuioCursor class encapsulates /tuio/2Dcur TUIO cursors. - * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioCursor: public TuioContainer { - - protected: - /** - * The individual cursor ID number that is assigned to each TuioCursor. - */ - int cursor_id; - - public: - using TuioContainer::update; - - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, Cursor ID, X and Y coordinate to the newly created TuioCursor. - * - * @param ttime the TuioTime to assign - * @param si the Session ID to assign - * @param ci the Cursor ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - TuioCursor (TuioTime ttime, long si, int ci, float xp, float yp); - - /** - * This constructor takes the provided Session ID, Cursor ID, X and Y coordinate - * and assigs these values to the newly created TuioCursor. - * - * @param si the Session ID to assign - * @param ci the Cursor ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - TuioCursor (long si, int ci, float xp, float yp); - - /** - * This constructor takes the atttibutes of the provided TuioCursor - * and assigs these values to the newly created TuioCursor. - * - * @param tcur the TuioCursor to assign - */ - TuioCursor (TuioCursor *tcur); - - /** - * The destructor is doing nothing in particular. - */ - virtual ~TuioCursor(){}; - - /** - * Returns the Cursor ID of this TuioCursor. - * @return the Cursor ID of this TuioCursor - */ - int getCursorID() const; - }; -} -#endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.cpp b/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.cpp deleted file mode 100644 index c36d59e282..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioDispatcher.h" - -#include -#include -#include -#include - -using namespace TUIO; - -TuioDispatcher::TuioDispatcher() { -#ifndef WIN32 - pthread_mutex_init(&cursorMutex,NULL); - pthread_mutex_init(&objectMutex,NULL); - pthread_mutex_init(&blobMutex,NULL); -#else - cursorMutex = CreateMutex(NULL,FALSE,TEXT("cursorMutex")); - objectMutex = CreateMutex(NULL,FALSE,TEXT("objectMutex")); - blobMutex = CreateMutex(NULL,FALSE,TEXT("blobMutex")); -#endif -} - -TuioDispatcher::~TuioDispatcher() { -#ifndef WIN32 - pthread_mutex_destroy(&cursorMutex); - pthread_mutex_destroy(&objectMutex); - pthread_mutex_destroy(&blobMutex); -#else - CloseHandle(cursorMutex); - CloseHandle(objectMutex); - CloseHandle(blobMutex); -#endif -} - -void TuioDispatcher::lockObjectList() { -#ifndef WIN32 - pthread_mutex_lock(&objectMutex); -#else - WaitForSingleObject(objectMutex, INFINITE); -#endif -} - -void TuioDispatcher::unlockObjectList() { -#ifndef WIN32 - pthread_mutex_unlock(&objectMutex); -#else - ReleaseMutex(objectMutex); -#endif -} - -void TuioDispatcher::lockCursorList() { -#ifndef WIN32 - pthread_mutex_lock(&cursorMutex); -#else - WaitForSingleObject(cursorMutex, INFINITE); -#endif -} - -void TuioDispatcher::unlockCursorList() { -#ifndef WIN32 - pthread_mutex_unlock(&cursorMutex); -#else - ReleaseMutex(cursorMutex); -#endif -} - -void TuioDispatcher::lockBlobList() { -#ifndef WIN32 - pthread_mutex_lock(&blobMutex); -#else - WaitForSingleObject(blobMutex, INFINITE); -#endif -} - -void TuioDispatcher::unlockBlobList() { -#ifndef WIN32 - pthread_mutex_unlock(&blobMutex); -#else - ReleaseMutex(blobMutex); -#endif -} - -void TuioDispatcher::addTuioListener(TuioListener *listener) { - listenerList.push_back(listener); -} - -void TuioDispatcher::removeTuioListener(TuioListener *listener) { - std::list::iterator result = find(listenerList.begin(),listenerList.end(),listener); - if (result!=listenerList.end()) listenerList.remove(listener); -} - -void TuioDispatcher::removeAllTuioListeners() { - listenerList.clear(); -} - -TuioObject* TuioDispatcher::getTuioObject(long s_id) { - lockObjectList(); - for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { - if((*iter)->getSessionID()==s_id) { - unlockObjectList(); - return (*iter); - } - } - unlockObjectList(); - return NULL; -} - -TuioCursor* TuioDispatcher::getTuioCursor(long s_id) { - lockCursorList(); - for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { - if((*iter)->getSessionID()==s_id) { - unlockCursorList(); - return (*iter); - } - } - unlockCursorList(); - return NULL; -} - -TuioBlob* TuioDispatcher::getTuioBlob(long s_id) { - lockBlobList(); - for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { - if((*iter)->getSessionID()==s_id) { - unlockBlobList(); - return (*iter); - } - } - unlockBlobList(); - return NULL; -} - -std::list TuioDispatcher::getTuioObjects() { - lockObjectList(); - std::list listBuffer; - listBuffer.insert(listBuffer.end(), objectList.begin(), objectList.end()); - //std::list listBuffer = objectList; - unlockObjectList(); - return listBuffer; -} - -std::list TuioDispatcher::getTuioCursors() { - lockCursorList(); - std::list listBuffer; - listBuffer.insert(listBuffer.end(), cursorList.begin(), cursorList.end()); - //std::list listBuffer = cursorList; - unlockCursorList(); - return listBuffer; -} - -std::list TuioDispatcher::getTuioBlobs() { - lockBlobList(); - std::list listBuffer; - listBuffer.insert(listBuffer.end(), blobList.begin(), blobList.end()); - //std::list listBuffer = blobList; - unlockBlobList(); - return listBuffer; -} - -std::list TuioDispatcher::copyTuioObjects() { - lockObjectList(); - std::list listBuffer; - for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { - TuioObject *tobj = (*iter); - listBuffer.push_back(*tobj); - } - unlockObjectList(); - return listBuffer; -} - -std::list TuioDispatcher::copyTuioCursors() { - lockCursorList(); - std::list listBuffer; - for (std::list::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { - TuioCursor *tcur = (*iter); - listBuffer.push_back(*tcur); - } - unlockCursorList(); - - return listBuffer; -} - -std::list TuioDispatcher::copyTuioBlobs() { - lockBlobList(); - std::list listBuffer; - for (std::list::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { - TuioBlob *tblb = (*iter); - listBuffer.push_back(*tblb); - } - unlockBlobList(); - return listBuffer; -} - - - diff --git a/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.h b/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.h deleted file mode 100644 index 0b8fc79fd2..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioDispatcher.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIODISPATCHER_H -#define INCLUDED_TUIODISPATCHER_H - -#include "TuioListener.h" - -#ifndef WIN32 -#include -#else -#include -#endif - -namespace TUIO { - - /** - *

The TuioDispatcher generates TUIO events which are broadcasted to all - * registered classes that implement the {@link TuioListener} interface.

- * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioDispatcher { - - public: - /** - * This constructor creates a TuioDispatcher - * - */ - TuioDispatcher(); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioDispatcher(); - - /** - * Adds the provided TuioListener to the list of registered TUIO event listeners - * - * @param listener the TuioListener to add - */ - void addTuioListener(TuioListener *listener); - - /** - * Removes the provided TuioListener from the list of registered TUIO event listeners - * - * @param listener the TuioListener to remove - */ - void removeTuioListener(TuioListener *listener); - - /** - * Removes all TuioListener from the list of registered TUIO event listeners - */ - void removeAllTuioListeners(); - - /** - * Returns a List of all currently active TuioObjects - * - * @return a List of all currently active TuioObjects - */ - std::list getTuioObjects(); - - /** - * Returns a List with a copy of currently active TuioObjects - * - * @return a List with a copy of all currently active TuioObjects - */ - std::list copyTuioObjects(); - - /** - * Returns a List of all currently active TuioCursors - * - * @return a List of all currently active TuioCursors - */ - std::list getTuioCursors(); - - /** - * Returns a List with a copy of currently active TuioCursors - * - * @return a List with a copy of all currently active TuioCursors - */ - std::list copyTuioCursors(); - - /** - * Returns a List of all currently active TuioBlobs - * - * @return a List of all currently active TuioBlobs - */ - std::list getTuioBlobs(); - - /** - * Returns a List with a copy of currently active TuioBlobs - * - * @return a List with a copy of all currently active TuioBlobs - */ - std::list copyTuioBlobs(); - - /** - * Returns the TuioObject corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioObject - * - * @return an active TuioObject corresponding to the provided Session ID or NULL - */ - TuioObject* getTuioObject(long s_id); - - /** - * Returns the TuioCursor corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioCursor - * - * @return an active TuioCursor corresponding to the provided Session ID or NULL - */ - TuioCursor* getTuioCursor(long s_id); - - /** - * Returns the TuioBlob corresponding to the provided Session ID - * or NULL if the Session ID does not refer to an active TuioBlob - * - * @return an active TuioBlob corresponding to the provided Session ID or NULL - */ - TuioBlob* getTuioBlob(long s_id); - - /** - * Locks the TuioObject list in order to avoid updates during access - */ - void lockObjectList(); - - /** - * Releases the lock of the TuioObject list - */ - void unlockObjectList(); - - /** - * Locks the TuioCursor list in order to avoid updates during access - */ - void lockCursorList(); - - /** - * Releases the lock of the TuioCursor list - */ - void unlockCursorList(); - - /** - * Locks the TuioBlob list in order to avoid updates during access - */ - void lockBlobList(); - - /** - * Releases the lock of the TuioBlob list - */ - void unlockBlobList(); - - protected: - std::list listenerList; - - std::list objectList; - std::list cursorList; - std::list blobList; - -#ifndef WIN32 - pthread_mutex_t objectMutex; - pthread_mutex_t cursorMutex; - pthread_mutex_t blobMutex; -#else - HANDLE objectMutex; - HANDLE cursorMutex; - HANDLE blobMutex; -#endif - - }; -} -#endif /* INCLUDED_TUIODISPATCHER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioListener.h b/modules/touch/ext/libTUIO/TUIO/TuioListener.h deleted file mode 100644 index 099f8805dd..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioListener.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOLISTENER_H -#define INCLUDED_TUIOLISTENER_H - -#include "TuioObject.h" -#include "TuioCursor.h" -#include "TuioBlob.h" - -namespace TUIO { - - /** - *

The TuioListener interface provides a simple callback infrastructure which is used by the {@link TuioClient} class - * to dispatch TUIO events to all registered instances of classes that implement the TuioListener interface defined here.

- *

Any class that implements the TuioListener interface is required to implement all of the callback methods defined here. - * The {@link TuioClient} makes use of these interface methods in order to dispatch TUIO events to all registered TuioListener implementations.

- *

- * public class MyTuioListener implements TuioListener
- * ...

- * MyTuioListener listener = new MyTuioListener();
- * TuioClient client = new TuioClient();
- * client.addTuioListener(listener);
- * client.start();
- *

- * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioListener { - - public: - /** - * The destructor is doing nothing in particular. - */ - virtual ~TuioListener(){}; - - /** - * This callback method is invoked by the TuioClient when a new TuioObject is added to the session. - * - * @param tobj the TuioObject reference associated to the addTuioObject event - */ - virtual void addTuioObject(TuioObject *tobj)=0; - - /** - * This callback method is invoked by the TuioClient when an existing TuioObject is updated during the session. - * - * @param tobj the TuioObject reference associated to the updateTuioObject event - */ - virtual void updateTuioObject(TuioObject *tobj)=0; - - /** - * This callback method is invoked by the TuioClient when an existing TuioObject is removed from the session. - * - * @param tobj the TuioObject reference associated to the removeTuioObject event - */ - virtual void removeTuioObject(TuioObject *tobj)=0; - - /** - * This callback method is invoked by the TuioClient when a new TuioCursor is added to the session. - * - * @param tcur the TuioCursor reference associated to the addTuioCursor event - */ - virtual void addTuioCursor(TuioCursor *tcur)=0; - - /** - * This callback method is invoked by the TuioClient when an existing TuioCursor is updated during the session. - * - * @param tcur the TuioCursor reference associated to the updateTuioCursor event - */ - virtual void updateTuioCursor(TuioCursor *tcur)=0; - - /** - * This callback method is invoked by the TuioClient when an existing TuioCursor is removed from the session. - * - * @param tcur the TuioCursor reference associated to the removeTuioCursor event - */ - virtual void removeTuioCursor(TuioCursor *tcur)=0; - - /** - * This callback method is invoked by the TuioClient when a new TuioBlob is added to the session. - * - * @param tcur the TuioBlob reference associated to the addTuioBlob event - */ - virtual void addTuioBlob(TuioBlob *tblb)=0; - - /** - * This callback method is invoked by the TuioClient when an existing TuioBlob is updated during the session. - * - * @param tblb the TuioBlob reference associated to the updateTuioBlob event - */ - virtual void updateTuioBlob(TuioBlob *tblb)=0; - - /** - * This callback method is invoked by the TuioClient when an existing TuioBlob is removed from the session. - * - * @param tblb the TuioBlob reference associated to the removeTuioBlob event - */ - virtual void removeTuioBlob(TuioBlob *tblb)=0; - - /** - * This callback method is invoked by the TuioClient to mark the end of a received TUIO message bundle. - * - * @param ftime the TuioTime associated to the current TUIO message bundle - */ - virtual void refresh(TuioTime ftime)=0; - }; -} -#endif /* INCLUDED_TUIOLISTENER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioManager.cpp b/modules/touch/ext/libTUIO/TUIO/TuioManager.cpp deleted file mode 100644 index db16a61d0f..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioManager.cpp +++ /dev/null @@ -1,615 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioManager.h" -using namespace TUIO; - - -TuioManager::TuioManager() - : currentFrameTime(TuioTime::getSystemTime()) - , currentFrame(-1) - , maxCursorID(-1) - , maxBlobID(-1) - , sessionID(-1) - , updateObject(false) - , updateCursor(false) - , updateBlob(false) - , verbose(false) - , invert_x(false) - , invert_y(false) - , invert_a(false) -{ - -} - -TuioManager::~TuioManager() { -} - - -TuioObject* TuioManager::addTuioObject(int f_id, float x, float y, float a) { - sessionID++; - TuioObject *tobj = new TuioObject(currentFrameTime, sessionID, f_id, x, y, a); - objectList.push_back(tobj); - updateObject = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioObject(tobj); - - if (verbose) - std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; - - return tobj; -} - -void TuioManager::addExternalTuioObject(TuioObject *tobj) { - if (tobj==NULL) return; - tobj->setSessionID(sessionID++); - objectList.push_back(tobj); - updateObject = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioObject(tobj); - - if (verbose) - std::cout << "add obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() << std::endl; -} - -void TuioManager::updateTuioObject(TuioObject *tobj, float x, float y, float a) { - if (tobj==NULL) return; - if (tobj->getTuioTime()==currentFrameTime) return; - tobj->update(currentFrameTime,x,y,a); - updateObject = true; - - if (tobj->isMoving()) { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioObject(tobj); - - if (verbose) - std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() - << " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; - } -} - -void TuioManager::updateExternalTuioObject(TuioObject *tobj) { - if (tobj==NULL) return; - updateObject = true; - - if (tobj->isMoving()) { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioObject(tobj); - - if (verbose) - std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() - << " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; - } -} - -void TuioManager::removeTuioObject(TuioObject *tobj) { - if (tobj==NULL) return; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioObject(tobj); - - if (verbose) - std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ")" << std::endl; - - objectList.remove(tobj); - delete tobj; - updateObject = true; -} - -void TuioManager::removeExternalTuioObject(TuioObject *tobj) { - if (tobj==NULL) return; - objectList.remove(tobj); - updateObject = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioObject(tobj); - - if (verbose) - std::cout << "del obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ")" << std::endl; -} - -TuioCursor* TuioManager::addTuioCursor(float x, float y) { - sessionID++; - - int cursorID = (int)cursorList.size(); - if ((int)(cursorList.size())<=maxCursorID) { - std::list::iterator closestCursor = freeCursorList.begin(); - - for(std::list::iterator iter = freeCursorList.begin();iter!= freeCursorList.end(); iter++) { - if((*iter)->getDistance(x,y)<(*closestCursor)->getDistance(x,y)) closestCursor = iter; - } - - TuioCursor *freeCursor = (*closestCursor); - cursorID = (*closestCursor)->getCursorID(); - freeCursorList.erase(closestCursor); - delete freeCursor; - } else maxCursorID = cursorID; - - TuioCursor *tcur = new TuioCursor(currentFrameTime, sessionID, cursorID, x, y); - cursorList.push_back(tcur); - updateCursor = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioCursor(tcur); - - if (verbose) - std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl; - - return tcur; -} - -void TuioManager::addExternalTuioCursor(TuioCursor *tcur) { - if (tcur==NULL) return; - tcur->setSessionID(sessionID++); - cursorList.push_back(tcur); - updateCursor = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioCursor(tcur); - - if (verbose) - std::cout << "add cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() << std::endl; -} - -void TuioManager::updateTuioCursor(TuioCursor *tcur,float x, float y) { - if (tcur==NULL) return; - //if (tcur->getTuioTime()==currentFrameTime) return; - tcur->update(currentFrameTime,x,y); - updateCursor = true; - - if (tcur->isMoving()) { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioCursor(tcur); - - if (verbose) - std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() - << " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl; - } -} - -void TuioManager::updateExternalTuioCursor(TuioCursor *tcur) { - if (tcur==NULL) return; - updateCursor = true; - - if (tcur->isMoving()) { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioCursor(tcur); - - if (verbose) - std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() - << " " << tcur->getXSpeed() << " " << tcur->getYSpeed() << " " << tcur->getMotionAccel() << " " << std::endl; - } -} - -void TuioManager::removeTuioCursor(TuioCursor *tcur) { - if (tcur==NULL) return; - - cursorList.remove(tcur); - tcur->remove(currentFrameTime); - updateCursor = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioCursor(tcur); - - if (verbose) - std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ")" << std::endl; - - if (tcur->getCursorID()==maxCursorID) { - maxCursorID = -1; - delete tcur; - - if (cursorList.size()>0) { - std::list::iterator clist; - for (clist=cursorList.begin(); clist != cursorList.end(); clist++) { - int cursorID = (*clist)->getCursorID(); - if (cursorID>maxCursorID) maxCursorID=cursorID; - } - - freeCursorBuffer.clear(); - for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { - TuioCursor *freeCursor = (*flist); - if (freeCursor->getCursorID()>maxCursorID) delete freeCursor; - else freeCursorBuffer.push_back(freeCursor); - } - - freeCursorList = freeCursorBuffer; - - } else { - for (std::list::iterator flist=freeCursorList.begin(); flist != freeCursorList.end(); flist++) { - TuioCursor *freeCursor = (*flist); - delete freeCursor; - } - freeCursorList.clear(); - } - } else if (tcur->getCursorID()::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioCursor(tcur); - - if (verbose) - std::cout << "del cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ")" << std::endl; -} - -TuioBlob* TuioManager::addTuioBlob(float x, float y, float a, float w, float h, float f) { - sessionID++; - - int blobID = (int)blobList.size(); - if ((int)(blobList.size())<=maxBlobID) { - std::list::iterator closestBlob = freeBlobList.begin(); - - for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) { - if((*iter)->getDistance(x,y)<(*closestBlob)->getDistance(x,y)) closestBlob = iter; - } - - TuioBlob *freeBlob = (*closestBlob); - blobID = (*closestBlob)->getBlobID(); - freeBlobList.erase(closestBlob); - delete freeBlob; - } else maxBlobID = blobID; - - TuioBlob *tblb = new TuioBlob(currentFrameTime, sessionID, blobID, x, y, a, w, h, f); - blobList.push_back(tblb); - updateBlob = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioBlob(tblb); - - if (verbose) - std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; - - return tblb; -} - -void TuioManager::addExternalTuioBlob(TuioBlob *tblb) { - if (tblb==NULL) return; - - int blobID = (int)blobList.size(); - if (blobID <= maxBlobID) { - std::list::iterator closestBlob = freeBlobList.begin(); - - for(std::list::iterator iter = freeBlobList.begin();iter!= freeBlobList.end(); iter++) { - if((*iter)->getDistance(tblb->getX(),tblb->getY())<(*closestBlob)->getDistance(tblb->getX(),tblb->getY())) closestBlob = iter; - } - - TuioBlob *freeBlob = (*closestBlob); - blobID = (*closestBlob)->getBlobID(); - freeBlobList.erase(closestBlob); - delete freeBlob; - } else maxBlobID = blobID; - - tblb->setSessionID(sessionID++); - tblb->setBlobID(blobID); - - blobList.push_back(tblb); - updateBlob = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->addTuioBlob(tblb); - - if (verbose) - std::cout << "add blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() << std::endl; -} - -void TuioManager::updateTuioBlob(TuioBlob *tblb,float x, float y, float a, float w, float h, float f) { - if (tblb==NULL) return; - if (tblb->getTuioTime()==currentFrameTime) return; - tblb->update(currentFrameTime,x,y,a,w,h,f); - updateBlob = true; - - if (tblb->isMoving()) { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioBlob(tblb); - - if (verbose) - std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() - << " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl; - } -} - -void TuioManager::updateExternalTuioBlob(TuioBlob *tblb) { - if (tblb==NULL) return; - updateBlob = true; - - if (tblb->isMoving()) { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->updateTuioBlob(tblb); - - if (verbose) - std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() - << " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl; - } -} - -void TuioManager::removeTuioBlob(TuioBlob *tblb) { - if (tblb==NULL) return; - - blobList.remove(tblb); - tblb->remove(currentFrameTime); - updateBlob = true; - - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioBlob(tblb); - - if (verbose) - std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ")" << std::endl; - - if (tblb->getBlobID()==maxBlobID) { - maxBlobID = -1; - delete tblb; - - if (blobList.size()>0) { - std::list::iterator clist; - for (clist=blobList.begin(); clist != blobList.end(); clist++) { - int blobID = (*clist)->getBlobID(); - if (blobID>maxBlobID) maxBlobID=blobID; - } - - freeBlobBuffer.clear(); - for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { - TuioBlob *freeBlob = (*flist); - if (freeBlob->getBlobID()>maxBlobID) delete freeBlob; - else freeBlobBuffer.push_back(freeBlob); - } - - freeBlobList = freeBlobBuffer; - - } else { - for (std::list::iterator flist=freeBlobList.begin(); flist != freeBlobList.end(); flist++) { - TuioBlob *freeBlob = (*flist); - delete freeBlob; - } - freeBlobList.clear(); - } - } else if (tblb->getBlobID()::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->removeTuioBlob(tblb); - - if (verbose) - std::cout << "del blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ")" << std::endl; -} - -long TuioManager::getSessionID() { - sessionID++; - return sessionID; -} - -long TuioManager::getFrameID() { - return currentFrame; -} - -TuioTime TuioManager::getFrameTime() { - return currentFrameTime; -} - -void TuioManager::initFrame(TuioTime ttime) { - currentFrameTime = TuioTime(ttime); - currentFrame++; -} - -void TuioManager::commitFrame() { - for (std::list::iterator listener=listenerList.begin(); listener != listenerList.end(); listener++) - (*listener)->refresh(currentFrameTime); -} - -TuioObject* TuioManager::getClosestTuioObject(float xp, float yp) { - - TuioObject *closestObject = NULL; - float closestDistance = 1.0f; - - for (std::list::iterator iter=objectList.begin(); iter != objectList.end(); iter++) { - float distance = (*iter)->getDistance(xp,yp); - if(distance::iterator iter=cursorList.begin(); iter != cursorList.end(); iter++) { - float distance = (*iter)->getDistance(xp,yp); - if(distance::iterator iter=blobList.begin(); iter != blobList.end(); iter++) { - float distance = (*iter)->getDistance(xp,yp); - if(distance TuioManager::getUntouchedObjects() { - - std::list untouched; - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { - TuioObject *tobj = (*tuioObject); - if (tobj->getTuioTime()!=currentFrameTime) untouched.push_back(tobj); - } - return untouched; -} - -void TuioManager::stopUntouchedMovingObjects() { - - std::list untouched; - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { - - TuioObject *tobj = (*tuioObject); - if ((tobj->getTuioTime()!=currentFrameTime) && (tobj->isMoving())) { - tobj->stop(currentFrameTime); - updateObject = true; - if (verbose) - std::cout << "set obj " << tobj->getSymbolID() << " (" << tobj->getSessionID() << ") "<< tobj->getX() << " " << tobj->getY() << " " << tobj->getAngle() - << " " << tobj->getXSpeed() << " " << tobj->getYSpeed() << " " << tobj->getRotationSpeed() << " " << tobj->getMotionAccel() << " " << tobj->getRotationAccel() << std::endl; - } - } -} - -void TuioManager::removeUntouchedStoppedObjects() { - - std::list::iterator tuioObject = objectList.begin(); - while (tuioObject!=objectList.end()) { - TuioObject *tobj = (*tuioObject); - if ((tobj->getTuioTime()!=currentFrameTime) && (!tobj->isMoving())) { - removeTuioObject(tobj); - tuioObject = objectList.begin(); - } else tuioObject++; - } -} - -void TuioManager::resetTuioObjects() { - - std::list::iterator tuioObject = objectList.begin(); - while (tuioObject!=objectList.end()) { - removeTuioObject((*tuioObject)); - tuioObject = objectList.begin(); - } -} - -std::list TuioManager::getUntouchedCursors() { - - std::list untouched; - for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { - TuioCursor *tcur = (*tuioCursor); - if (tcur->getTuioTime()!=currentFrameTime) untouched.push_back(tcur); - } - return untouched; -} - -void TuioManager::stopUntouchedMovingCursors() { - - std::list untouched; - for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { - TuioCursor *tcur = (*tuioCursor); - if ((tcur->getTuioTime()!=currentFrameTime) && (tcur->isMoving())) { - tcur->stop(currentFrameTime); - updateCursor = true; - if (verbose) - std::cout << "set cur " << tcur->getCursorID() << " (" << tcur->getSessionID() << ") " << tcur->getX() << " " << tcur->getY() - << " " << tcur->getXSpeed() << " " << tcur->getYSpeed()<< " " << tcur->getMotionAccel() << " " << std::endl; - } - } -} - -void TuioManager::removeUntouchedStoppedCursors() { - - if (cursorList.size()==0) return; - std::list::iterator tuioCursor = cursorList.begin(); - while (tuioCursor!=cursorList.end()) { - TuioCursor *tcur = (*tuioCursor); - if ((tcur->getTuioTime()!=currentFrameTime) && (!tcur->isMoving())) { - removeTuioCursor(tcur); - tuioCursor = cursorList.begin(); - } else tuioCursor++; - } -} - -void TuioManager::resetTuioCursors() { - - std::list::iterator tuioCursor = cursorList.begin(); - while (tuioCursor!=cursorList.end()) { - removeTuioCursor((*tuioCursor)); - tuioCursor = cursorList.begin(); - } -} - -std::list TuioManager::getUntouchedBlobs() { - - std::list untouched; - for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { - TuioBlob *tblb = (*tuioBlob); - if (tblb->getTuioTime()!=currentFrameTime) untouched.push_back(tblb); - } - return untouched; -} - -void TuioManager::stopUntouchedMovingBlobs() { - - std::list untouched; - for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { - TuioBlob *tblb = (*tuioBlob); - if ((tblb->getTuioTime()!=currentFrameTime) && (tblb->isMoving())) { - tblb->stop(currentFrameTime); - updateBlob = true; - if (verbose) - std::cout << "set blb " << tblb->getBlobID() << " (" << tblb->getSessionID() << ") " << tblb->getX() << " " << tblb->getY() << " " << tblb->getAngle() << " " << tblb->getWidth() << " " << tblb->getHeight() << " " << tblb->getArea() - << " " << tblb->getXSpeed() << " " << tblb->getYSpeed() << " " << tblb->getRotationSpeed() << " " << tblb->getMotionAccel()<< " " << tblb->getRotationAccel() << " " << std::endl; - } - } -} - -void TuioManager::removeUntouchedStoppedBlobs() { - - std::list::iterator tuioBlob = blobList.begin(); - while (tuioBlob!=blobList.end()) { - TuioBlob *tblb = (*tuioBlob); - if ((tblb->getTuioTime()!=currentFrameTime) && (!tblb->isMoving())) { - removeTuioBlob(tblb); - tuioBlob = blobList.begin(); - } else tuioBlob++; - } -} - -void TuioManager::resetTuioBlobs() { - - std::list::iterator tuioBlob = blobList.begin(); - while (tuioBlob!=blobList.end()) { - removeTuioBlob((*tuioBlob)); - tuioBlob = blobList.begin(); - } -} diff --git a/modules/touch/ext/libTUIO/TUIO/TuioManager.h b/modules/touch/ext/libTUIO/TUIO/TuioManager.h deleted file mode 100644 index 3eabbde47b..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioManager.h +++ /dev/null @@ -1,389 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOMANAGER_H -#define INCLUDED_TUIOMANAGER_H - -#include "TuioDispatcher.h" - -#include -#include -#include - -#define OBJ_MESSAGE_SIZE 108 // setMessage + fseqMessage size -#define CUR_MESSAGE_SIZE 88 -#define BLB_MESSAGE_SIZE 116 - -namespace TUIO { - /** - *

The TuioManager class is the central TUIO session management component.

- *

During runtime the each frame is marked with the initFrame and commitFrame methods, - * while the currently present TuioObjects are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

- *

- * TuioManager *manager = new TuioManager();
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * TuioObject *tobj = server->addTuioObject(xpos,ypos, angle);
- * TuioCursor *tcur = server->addTuioObject(xpos,ypos);
- * TuioBlob *tblb = server->addTuioBlob(xpos,ypos,width,height,angle);
- * server->commitFrame();
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * server->updateTuioObject(tobj, xpos,ypos, angle);
- * server->updateTuioCursor(tcur, xpos,ypos);
- * server->updateTuioBlob(tblb, xpos,ypos,width,height,angle);
- * server->commitFrame();
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * server->removeTuioObject(tobj);
- * server->removeTuioCursor(tcur);
- * server->removeTuioBlob(tblb);
- * server->commitFrame();
- *

- * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioManager : public TuioDispatcher { - - public: - - /** - * The default constructor creates a TuioManager - */ - TuioManager(); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioManager(); - - /** - * Creates a new TuioObject based on the given arguments. - * The new TuioObject is added to the TuioServer's internal list of active TuioObjects - * and a reference is returned to the caller. - * - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - * @return reference to the created TuioObject - */ - TuioObject* addTuioObject(int sym, float xp, float yp, float a); - - /** - * Updates the referenced TuioObject based on the given arguments. - * - * @param tobj the TuioObject to update - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - void updateTuioObject(TuioObject *tobj, float xp, float yp, float a); - - /** - * Removes the referenced TuioObject from the TuioServer's internal list of TuioObjects - * and deletes the referenced TuioObject afterwards - * - * @param tobj the TuioObject to remove - */ - void removeTuioObject(TuioObject *tobj); - - /** - * Adds an externally managed TuioObject to the TuioServer's internal list of active TuioObjects - * - * @param tobj the TuioObject to add - */ - void addExternalTuioObject(TuioObject *tobj); - - /** - * Updates an externally managed TuioObject - * - * @param tobj the TuioObject to update - */ - void updateExternalTuioObject(TuioObject *tobj); - - /** - * Removes an externally managed TuioObject from the TuioServer's internal list of TuioObjects - * The referenced TuioObject is not deleted - * - * @param tobj the TuioObject to remove - */ - void removeExternalTuioObject(TuioObject *tobj); - - /** - * Creates a new TuioCursor based on the given arguments. - * The new TuioCursor is added to the TuioServer's internal list of active TuioCursors - * and a reference is returned to the caller. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @return reference to the created TuioCursor - */ - TuioCursor* addTuioCursor(float xp, float yp); - - /** - * Updates the referenced TuioCursor based on the given arguments. - * - * @param tcur the TuioObject to update - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - void updateTuioCursor(TuioCursor *tcur, float xp, float yp); - - /** - * Removes the referenced TuioCursor from the TuioServer's internal list of TuioCursors - * and deletes the referenced TuioCursor afterwards - * - * @param tcur the TuioCursor to remove - */ - void removeTuioCursor(TuioCursor *tcur); - - /** - * Adds an externally managed TuioCursor - * - * @param tcur the TuioCursor to add - */ - void addExternalTuioCursor(TuioCursor *tcur); - - /** - * Updates an externally managed TuioCursor - * - * @param tcur the TuioCursor to update - */ - void updateExternalTuioCursor(TuioCursor *tcur); - - /** - * Removes an externally managed TuioCursor from the TuioServer's internal list of TuioCursor - * The referenced TuioCursor is not deleted - * - * @param tcur the TuioCursor to remove - */ - void removeExternalTuioCursor(TuioCursor *tcur); - - /** - * Creates a new TuioBlob based on the given arguments. - * The new TuioBlob is added to the TuioServer's internal list of active TuioBlobs - * and a reference is returned to the caller. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param angle the angle to assign - * @param width the width to assign - * @param height the height to assign - * @param area the area to assign - * @return reference to the created TuioBlob - */ - TuioBlob* addTuioBlob(float xp, float yp, float angle, float width, float height, float area); - - /** - * Updates the referenced TuioBlob based on the given arguments. - * - * @param tblb the TuioObject to update - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param angle the angle to assign - * @param width the width to assign - * @param height the height to assign - * @param area the area to assign - */ - void updateTuioBlob(TuioBlob *tblb, float xp, float yp, float angle, float width, float height, float area); - - /** - * Removes the referenced TuioBlob from the TuioServer's internal list of TuioBlobs - * and deletes the referenced TuioBlob afterwards - * - * @param tblb the TuioBlob to remove - */ - void removeTuioBlob(TuioBlob *tblb); - - /** - * Updates an externally managed TuioBlob - * - * @param tblb the TuioBlob to update - */ - void addExternalTuioBlob(TuioBlob *tblb); - - /** - * Updates an externally managed TuioBlob - * - * @param tblb the TuioBlob to update - */ - void updateExternalTuioBlob(TuioBlob *tblb); - - /** - * Removes an externally managed TuioBlob from the TuioServer's internal list of TuioBlob - * The referenced TuioBlob is not deleted - * - * @param tblb the TuioBlob to remove - */ - void removeExternalTuioBlob(TuioBlob *tblb); - - /** - * Initializes a new frame with the given TuioTime - * - * @param ttime the frame time - */ - void initFrame(TuioTime ttime); - - /** - * Commits the current frame. - * Generates and sends TUIO messages of all currently active and updated TuioObjects and TuioCursors. - */ - void commitFrame(); - - /** - * Returns the next available Session ID for external use. - * @return the next available Session ID for external use - */ - long getSessionID(); - - /** - * Returns the current frame ID for external use. - * @return the current frame ID for external use - */ - long getFrameID(); - - /** - * Returns the current frame ID for external use. - * @return the current frame ID for external use - */ - TuioTime getFrameTime(); - - /** - * Returns a List of all currently inactive TuioObjects - * - * @return a List of all currently inactive TuioObjects - */ - std::list getUntouchedObjects(); - - /** - * Returns a List of all currently inactive TuioCursors - * - * @return a List of all currently inactive TuioCursors - */ - std::list getUntouchedCursors(); - - /** - * Returns a List of all currently inactive TuioBlobs - * - * @return a List of all currently inactive TuioBlobs - */ - std::list getUntouchedBlobs(); - - /** - * Calculates speed and acceleration values for all currently inactive TuioObjects - */ - void stopUntouchedMovingObjects(); - - /** - * Calculates speed and acceleration values for all currently inactive TuioCursors - */ - void stopUntouchedMovingCursors(); - - /** - * Calculates speed and acceleration values for all currently inactive TuioBlobs - */ - void stopUntouchedMovingBlobs(); - - /** - * Removes all currently inactive TuioObjects from the TuioServer's internal list of TuioObjects - */ - void removeUntouchedStoppedObjects(); - - /** - * Removes all currently inactive TuioCursors from the TuioServer's internal list of TuioCursors - */ - void removeUntouchedStoppedCursors(); - - /** - * Removes all currently inactive TuioCursors from the TuioServer's internal list of TuioBlobs - */ - void removeUntouchedStoppedBlobs(); - - /** - * Returns the TuioObject closest to the provided coordinates - * or NULL if there isn't any active TuioObject - * - * @return the closest TuioObject to the provided coordinates or NULL - */ - TuioObject* getClosestTuioObject(float xp, float yp); - - /** - * Returns the TuioCursor closest to the provided coordinates - * or NULL if there isn't any active TuioCursor - * - * @return the closest TuioCursor corresponding to the provided coordinates or NULL - */ - TuioCursor* getClosestTuioCursor(float xp, float yp); - - /** - * Returns the TuioBlob closest to the provided coordinates - * or NULL if there isn't any active TuioBlob - * - * @return the closest TuioBlob corresponding to the provided coordinates or NULL - */ - TuioBlob* getClosestTuioBlob(float xp, float yp); - - /** - * The TuioServer prints verbose TUIO event messages to the console if set to true. - * @param verbose print verbose messages if set to true - */ - void setVerbose(bool verbose) { this->verbose=verbose; } - bool isVerbose() { return verbose; } - - void setInversion(bool ix, bool iy, bool ia) { - invert_x = ix; - invert_y = iy; - invert_a = ia; - }; - - void setInvertXpos(bool ix) { invert_x = ix; }; - void setInvertYpos(bool iy) { invert_y = iy; }; - void setInvertAngle(bool ia) { invert_a = ia; }; - bool getInvertXpos() { return invert_x; }; - bool getInvertYpos() { return invert_y; }; - bool getInvertAngle() { return invert_a; }; - void resetTuioObjects(); - void resetTuioCursors(); - void resetTuioBlobs(); - - protected: - std::list freeCursorList; - std::list freeCursorBuffer; - - std::list freeBlobList; - std::list freeBlobBuffer; - - TuioTime currentFrameTime; - long currentFrame; - int maxCursorID; - int maxBlobID; - long sessionID; - - bool updateObject; - bool updateCursor; - bool updateBlob; - bool verbose; - - bool invert_x; - bool invert_y; - bool invert_a; - }; -} -#endif /* INCLUDED_TUIOMANAGER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioObject.cpp b/modules/touch/ext/libTUIO/TUIO/TuioObject.cpp deleted file mode 100644 index 9c818ca37c..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioObject.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioObject.h" - -using namespace TUIO; - -TuioObject::TuioObject (TuioTime ttime, long si, int sym, float xp, float yp, float a):TuioContainer(ttime, si, xp, yp) { - symbol_id = sym; - angle = a; - angle_sum = a; - rotation_speed = 0.0f; - rotation_accel = 0.0f; - - angleFilter = NULL; - angleThreshold = 0.0f; -} - -TuioObject::TuioObject (long si, int sym, float xp, float yp, float a):TuioContainer(si, xp, yp) { - symbol_id = sym; - angle = a; - angle_sum = a; - rotation_speed = 0.0f; - rotation_accel = 0.0f; - - angleFilter = NULL; - angleThreshold = 0.0f; -} - -TuioObject::TuioObject (TuioObject *tobj):TuioContainer(tobj) { - symbol_id = tobj->getSymbolID(); - angle = tobj->getAngle(); - angle_sum = tobj->getAngleSum(); - rotation_speed = 0.0f; - rotation_accel = 0.0f; - - angleFilter = NULL; - angleThreshold = 0.0f; -} - -void TuioObject::update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { - TuioContainer::update(ttime,xp,yp,xs,ys,ma); - angle = a; - angle_sum = a; - rotation_speed = rs; - rotation_accel = ra; - if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; -} - - -void TuioObject::update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra) { - TuioContainer::update(xp,yp,xs,ys,ma); - angle = a; - angle_sum = a; - rotation_speed = rs; - rotation_accel = ra; - if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; -} - -void TuioObject::update (TuioTime ttime, float xp, float yp, float a) { - TuioPoint lastPoint = path.back(); - TuioContainer::update(ttime,xp,yp); - - TuioTime diffTime = currentTime - lastPoint.getTuioTime(); - float dt = diffTime.getTotalMilliseconds()/1000.0f; - float last_rotation_speed = rotation_speed; - - float prev_angle = angle_sum; - float da = a-angle; - if (da > M_PI/2.0f) angle_sum += (da-2*M_PI); - else if (da < M_PI/-2.0f) angle_sum += (da+2*M_PI); - else angle_sum += da; - - if (angleFilter) angle_sum = angleFilter->filter(angle_sum,dt); - if (fabs(angle_sum-prev_angle) 0.75f) da-=1.0f; - else if (da < -0.75f) da+=1.0f; - - rotation_speed = (float)da/dt; - rotation_accel = (rotation_speed - last_rotation_speed)/dt; - - if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; -} - -void TuioObject::stop (TuioTime ttime) { - update(ttime,xpos,ypos,angle); -} - -void TuioObject::update (TuioObject *tobj) { - TuioContainer::update(tobj); - angle = tobj->getAngle(); - angle_sum = tobj->getAngleSum(); - rotation_speed = tobj->getRotationSpeed(); - rotation_accel = tobj->getRotationAccel(); - if ((rotation_accel!=0) && (state==TUIO_STOPPED)) state = TUIO_ROTATING; -} - -int TuioObject::getSymbolID() const{ - return symbol_id; -} - -float TuioObject::getAngle() const{ - return angle; -} - -float TuioObject::getAngleSum() const{ - return angle_sum; -} - -float TuioObject::getAngleDegrees() const{ - return (float)(angle/M_PI*180); -} - -float TuioObject::getRotationSpeed() const{ - return rotation_speed; -} - -float TuioObject::getRotationAccel() const{ - return rotation_accel; -} - -bool TuioObject::isMoving() const{ - if ((state==TUIO_ACCELERATING) || (state==TUIO_DECELERATING) || (state==TUIO_ROTATING)) return true; - else return false; -} - -void TuioObject::addAngleThreshold(float thresh) { - angleThreshold = thresh; -} - -void TuioObject::removeAngleThreshold() { - angleThreshold = 0.0f; -} - -void TuioObject::addAngleFilter(float mcut, float beta) { - - if (angleFilter) delete angleFilter; - angleFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); -} - -void TuioObject::removeAngleFilter() { - - if (angleFilter) delete angleFilter; - angleFilter = NULL; -} diff --git a/modules/touch/ext/libTUIO/TUIO/TuioObject.h b/modules/touch/ext/libTUIO/TUIO/TuioObject.h deleted file mode 100644 index b027c79fe3..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioObject.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOOBJECT_H -#define INCLUDED_TUIOOBJECT_H - -#include "TuioContainer.h" - -namespace TUIO { - - /** - * The TuioObject class encapsulates /tuio/2Dobj TUIO objects. - * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioObject: public TuioContainer { - - protected: - /** - * The individual symbol ID number that is assigned to each TuioObject. - */ - int symbol_id; - /** - * The rotation angle value. - */ - float angle; - /** - * The accumulated angle value. - */ - float angle_sum; - /** - * The rotation speed value. - */ - float rotation_speed; - /** - * The rotation acceleration value. - */ - float rotation_accel; - - float angleThreshold; - OneEuroFilter *angleFilter; - - public: - using TuioContainer::update; - - /** - * This constructor takes a TuioTime argument and assigns it along with the provided - * Session ID, Symbol ID, X and Y coordinate and angle to the newly created TuioObject. - * - * @param ttime the TuioTime to assign - * @param si the Session ID to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - TuioObject (TuioTime ttime, long si, int sym, float xp, float yp, float a); - - /** - * This constructor takes the provided Session ID, Symbol ID, X and Y coordinate - * and angle, and assigs these values to the newly created TuioObject. - * - * @param si the Session ID to assign - * @param sym the Symbol ID to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle to assign - */ - TuioObject (long si, int sym, float xp, float yp, float a); - - /** - * This constructor takes the atttibutes of the provided TuioObject - * and assigs these values to the newly created TuioObject. - * - * @param tobj the TuioObject to assign - */ - TuioObject (TuioObject *tobj); - - /** - * The destructor is doing nothing in particular. - */ - virtual ~TuioObject() { - if (angleFilter) delete angleFilter; - }; - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate, angle, X and Y velocity, motion acceleration, - * rotation speed and rotation acceleration to the private TuioObject attributes. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle coordinate to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param rs the rotation velocity to assign - * @param ma the motion acceleration to assign - * @param ra the rotation acceleration to assign - */ - void update (TuioTime ttime, float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); - - /** - * Assigns the provided X and Y coordinate, angle, X and Y velocity, motion acceleration - * rotation velocity and rotation acceleration to the private TuioContainer attributes. - * The TuioTime time stamp remains unchanged. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle coordinate to assign - * @param xs the X velocity to assign - * @param ys the Y velocity to assign - * @param rs the rotation velocity to assign - * @param ma the motion acceleration to assign - * @param ra the rotation acceleration to assign - */ - void update (float xp, float yp, float a, float xs, float ys, float rs, float ma, float ra); - - /** - * Takes a TuioTime argument and assigns it along with the provided - * X and Y coordinate and angle to the private TuioObject attributes. - * The speed and accleration values are calculated accordingly. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - * @param a the angle coordinate to assign - */ - void update (TuioTime ttime, float xp, float yp, float a); - - /** - * This method is used to calculate the speed and acceleration values of a - * TuioObject with unchanged position and angle. - */ - void stop (TuioTime ttime); - - /** - * Takes the atttibutes of the provided TuioObject - * and assigs these values to this TuioObject. - * The TuioTime time stamp of this TuioContainer remains unchanged. - * - * @param tobj the TuioContainer to assign - */ - void update (TuioObject *tobj); - - /** - * Returns the symbol ID of this TuioObject. - * @return the symbol ID of this TuioObject - */ - int getSymbolID() const; - - /** - * Returns the rotation angle of this TuioObject. - * @return the rotation angle of this TuioObject - */ - float getAngle() const; - - /** - * Returns the accumulated rotation angle of this TuioObject. - * @return the accumulated rotation angle of this TuioObject - */ - float getAngleSum() const; - - /** - * Returns the rotation angle in degrees of this TuioObject. - * @return the rotation angle in degrees of this TuioObject - */ - float getAngleDegrees() const; - - /** - * Returns the rotation speed of this TuioObject. - * @return the rotation speed of this TuioObject - */ - float getRotationSpeed() const; - - /** - * Returns the rotation acceleration of this TuioObject. - * @return the rotation acceleration of this TuioObject - */ - float getRotationAccel() const; - - /** - * Returns true of this TuioObject is moving. - * @return true of this TuioObject is moving - */ - bool isMoving() const; - - void addAngleThreshold(float thresh); - - void removeAngleThreshold(); - - void addAngleFilter(float mcut, float beta); - - void removeAngleFilter(); - }; -} -#endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioPoint.cpp b/modules/touch/ext/libTUIO/TUIO/TuioPoint.cpp deleted file mode 100644 index 0b0761c435..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioPoint.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioPoint.h" - -using namespace TUIO; - -TuioPoint::TuioPoint (float xp, float yp) { - xpos = xp; - ypos = yp; - currentTime = TuioTime::getSessionTime(); - startTime = currentTime; - - xposFilter = NULL; - yposFilter = NULL; - - posThreshold = 0.0f; -} - -TuioPoint::TuioPoint (TuioTime ttime, float xp, float yp) { - xpos = xp; - ypos = yp; - currentTime = ttime; - startTime = currentTime; - - xposFilter = NULL; - yposFilter = NULL; - - posThreshold = 0.0f; -} - -TuioPoint::TuioPoint (TuioPoint *tpoint) { - xpos = tpoint->getX(); - ypos = tpoint->getY(); - currentTime = TuioTime::getSessionTime(); - startTime = currentTime; - - xposFilter = NULL; - yposFilter = NULL; - - posThreshold = 0.0f; -} - -void TuioPoint::update (TuioPoint *tpoint) { - xpos = tpoint->getX(); - ypos = tpoint->getY(); -} - -void TuioPoint::update (float xp, float yp) { - xpos = xp; - ypos = yp; -} - -void TuioPoint::update (TuioTime ttime, float xp, float yp) { - - if (xposFilter && yposFilter) { - TuioTime diffTime = ttime - startTime; - float dt = diffTime.getTotalMilliseconds()/1000.0f; - xp = xposFilter->filter(xp,dt); - yp = yposFilter->filter(yp,dt); - //std::cout << dt << " " << xp << " " << xpos << " " << yp << " " << ypos << std::endl; - } - - float dx = fabs(xpos - xp); - float dy = fabs(ypos - yp); - if ((dx>posThreshold) || (dy>posThreshold)) { - xpos = xp; - ypos = yp; - } - - currentTime = ttime; -} - - -float TuioPoint::getX() const{ - return xpos; -} - -float TuioPoint::getY() const{ - return ypos; -} - -float TuioPoint::getDistance(float xp, float yp) const{ - float dx = xpos-xp; - float dy = ypos-yp; - return sqrtf(dx*dx+dy*dy); -} - -float TuioPoint::getScreenDistance(float xp, float yp, int w, int h) const{ - float dx = w*xpos-w*xp; - float dy = h*ypos-h*yp; - return sqrtf(dx*dx+dy*dy); -} - -float TuioPoint::getDistance(TuioPoint *tpoint) const{ - return getDistance(tpoint->getX(),tpoint->getY()); -} - - -float TuioPoint::getAngle(float xp, float yp) const{ - float side = xpos-xp; - float height = ypos-yp; - float distance = getDistance(xp,yp); - - float angle = (float)(asin(side/distance)+M_PI/2); - if (height<0) angle = 2.0f*(float)M_PI-angle; - - return angle; -} - -float TuioPoint::getAngle(TuioPoint *tpoint) const{ - return getAngle(tpoint->getX(),tpoint->getY()); -} - -float TuioPoint::getAngleDegrees(float xp, float yp) const{ - return ((getAngle(xp,yp)/(float)M_PI)*180.0f); -} - -float TuioPoint::getAngleDegrees(TuioPoint *tpoint) const{ - return ((getAngle(tpoint)/(float)M_PI)*180.0f); -} - -int TuioPoint::getScreenX(int width) const{ - return (int)floor(xpos*width+0.5f); -} - -int TuioPoint::getScreenY(int height) const{ - return (int)floor(ypos*height+0.5f); -} - -TuioTime TuioPoint::getTuioTime() const{ - return currentTime; -} - -TuioTime TuioPoint::getStartTime() const{ - return startTime; -} - -void TuioPoint::addPositionThreshold(float thresh) { - posThreshold = thresh; -} - -void TuioPoint::removePositionThreshold() { - posThreshold = 0.0f; -} - -void TuioPoint::addPositionFilter(float mcut, float beta) { - - if (xposFilter) delete xposFilter; - xposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); - if (yposFilter) delete yposFilter; - yposFilter = new OneEuroFilter(60.0f, mcut, beta, 1.0f); -} - -void TuioPoint::removePositionFilter() { - - if (xposFilter) delete xposFilter; - xposFilter = NULL; - if (yposFilter) delete yposFilter; - yposFilter = NULL; -} diff --git a/modules/touch/ext/libTUIO/TUIO/TuioPoint.h b/modules/touch/ext/libTUIO/TUIO/TuioPoint.h deleted file mode 100644 index 3415f07312..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioPoint.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOPOINT_H -#define INCLUDED_TUIOPOINT_H - -#include "TuioTime.h" -#include "OneEuroFilter.h" -#include - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -namespace TUIO { - - /** - * The TuioPoint class on the one hand is a simple container and utility class to handle TUIO positions in general, - * on the other hand the TuioPoint is the base class for the TuioCursor and TuioObject classes. - * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioPoint { - - protected: - /** - * X coordinate, representated as a floating point value in a range of 0..1 - */ - float xpos; - /** - * X coordinate, representated as a floating point value in a range of 0..1 - */ - float ypos; - /** - * The time stamp of the last update represented as TuioTime (time since session start) - */ - TuioTime currentTime; - /** - * The creation time of this TuioPoint represented as TuioTime (time since session start) - */ - TuioTime startTime; - - OneEuroFilter *xposFilter; - OneEuroFilter *yposFilter; - float posThreshold; - - public: - /** - * The default constructor takes no arguments and sets - * its coordinate attributes to zero and its time stamp to the current session time. - */ - TuioPoint (float xp, float yp); - - /** - * This constructor takes a TuioTime object and two floating point coordinate arguments and sets - * its coordinate attributes to these values and its time stamp to the provided TUIO time object. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - TuioPoint (TuioTime ttime, float xp, float yp); - - /** - * This constructor takes a TuioPoint argument and sets its coordinate attributes - * to the coordinates of the provided TuioPoint and its time stamp to the current session time. - * - * @param tpoint the TuioPoint to assign - */ - TuioPoint (TuioPoint *tpoint); - - /** - * The destructor is doing nothing in particular. - */ - virtual ~TuioPoint(){ - if (xposFilter) delete xposFilter; - if (yposFilter) delete yposFilter; - }; - - /** - * Takes a TuioPoint argument and updates its coordinate attributes - * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. - * - * @param tpoint the TuioPoint to assign - */ - void update (TuioPoint *tpoint); - - /** - * Takes two floating point coordinate arguments and updates its coordinate attributes - * to the coordinates of the provided TuioPoint and leaves its time stamp unchanged. - * - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - void update (float xp, float yp); - - /** - * Takes a TuioTime object and two floating point coordinate arguments and updates its coordinate attributes - * to the coordinates of the provided TuioPoint and its time stamp to the provided TUIO time object. - * - * @param ttime the TuioTime to assign - * @param xp the X coordinate to assign - * @param yp the Y coordinate to assign - */ - void update (TuioTime ttime, float xp, float yp); - - - /** - * Returns the X coordinate of this TuioPoint. - * @return the X coordinate of this TuioPoint - */ - float getX() const; - - /** - * Returns the Y coordinate of this TuioPoint. - * @return the Y coordinate of this TuioPoint - */ - float getY() const; - - /** - * Returns the distance to the provided coordinates - * - * @param xp the X coordinate of the distant point - * @param yp the Y coordinate of the distant point - * @return the distance to the provided coordinates - */ - float getDistance(float xp, float yp) const; - - /** - * Returns the distance to the provided coordinates - * - * @param xp the X coordinate of the distant point - * @param yp the Y coordinate of the distant point - * @return the distance to the provided coordinates - */ - float getScreenDistance(float xp, float yp, int w, int h) const; - /** - * Returns the distance to the provided TuioPoint - * - * @param tpoint the distant TuioPoint - * @return the distance to the provided TuioPoint - */ - float getDistance(TuioPoint *tpoint) const; - /** - * Returns the angle to the provided coordinates - * - * @param xp the X coordinate of the distant point - * @param yp the Y coordinate of the distant point - * @return the angle to the provided coordinates - */ - float getAngle(float xp, float yp) const; - /** - * Returns the angle to the provided TuioPoint - * - * @param tpoint the distant TuioPoint - * @return the angle to the provided TuioPoint - */ - float getAngle(TuioPoint *tpoint) const; - /** - * Returns the angle in degrees to the provided coordinates - * - * @param xp the X coordinate of the distant point - * @param yp the Y coordinate of the distant point - * @return the angle in degrees to the provided TuioPoint - */ - float getAngleDegrees(float xp, float yp) const; - /** - * Returns the angle in degrees to the provided TuioPoint - * - * @param tpoint the distant TuioPoint - * @return the angle in degrees to the provided TuioPoint - */ - float getAngleDegrees(TuioPoint *tpoint) const; - /** - * Returns the X coordinate in pixels relative to the provided screen width. - * - * @param width the screen width - * @return the X coordinate of this TuioPoint in pixels relative to the provided screen width - */ - int getScreenX(int width) const; - /* - * Returns the Y coordinate in pixels relative to the provided screen height. - * - * @param height the screen height - * @return the Y coordinate of this TuioPoint in pixels relative to the provided screen height - */ - int getScreenY(int height) const; - /** - * Returns current time stamp of this TuioPoint as TuioTime - * - * @return the time stamp of this TuioPoint as TuioTime - */ - TuioTime getTuioTime() const; - /** - * Returns the start time of this TuioPoint as TuioTime. - * - * @return the start time of this TuioPoint as TuioTime - */ - TuioTime getStartTime() const; - - void addPositionThreshold(float thresh); - - void removePositionThreshold(); - - void addPositionFilter(float mcut, float beta); - - void removePositionFilter(); - }; -} -#endif diff --git a/modules/touch/ext/libTUIO/TUIO/TuioServer.cpp b/modules/touch/ext/libTUIO/TUIO/TuioServer.cpp deleted file mode 100644 index c157e7dc09..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioServer.cpp +++ /dev/null @@ -1,634 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioServer.h" -#include "UdpSender.h" - -using namespace TUIO; -using namespace osc; - -TuioServer::TuioServer() - :full_update (false) - ,periodic_update (false) - ,objectProfileEnabled (true) - ,cursorProfileEnabled (true) - ,blobProfileEnabled (true) - ,source_name (NULL) -{ - OscSender *oscsend = new UdpSender(); - initialize(oscsend); -} - -TuioServer::TuioServer(const char *host, int port) -:full_update (false) -,periodic_update (false) -,objectProfileEnabled (true) -,cursorProfileEnabled (true) -,blobProfileEnabled (true) -,source_name (NULL) -{ - OscSender *oscsend = new UdpSender(host,port); - initialize(oscsend); -} - -TuioServer::TuioServer(OscSender *oscsend) - :full_update (false) - ,periodic_update (false) - ,objectProfileEnabled (true) - ,cursorProfileEnabled (true) - ,blobProfileEnabled (true) - ,source_name (NULL) -{ - initialize(oscsend); -} - -void TuioServer::initialize(OscSender *oscsend) { - - senderList.push_back(oscsend); - int size = oscsend->getBufferSize(); - oscBuffer = new char[size]; - oscPacket = new osc::OutboundPacketStream(oscBuffer,size); - fullBuffer = new char[size]; - fullPacket = new osc::OutboundPacketStream(oscBuffer,size); - - objectUpdateTime = TuioTime(currentFrameTime); - cursorUpdateTime = TuioTime(currentFrameTime); - blobUpdateTime = TuioTime(currentFrameTime); - - if (cursorProfileEnabled) sendEmptyCursorBundle(); - if (objectProfileEnabled) sendEmptyObjectBundle(); - if (blobProfileEnabled) sendEmptyBlobBundle(); - - invert_x = false; - invert_y = false; - invert_a = false; -} - -TuioServer::~TuioServer() { - - initFrame(TuioTime::getSessionTime()); - stopUntouchedMovingCursors(); - stopUntouchedMovingObjects(); - stopUntouchedMovingBlobs(); - - initFrame(TuioTime::getSessionTime()); - removeUntouchedStoppedCursors(); - removeUntouchedStoppedObjects(); - removeUntouchedStoppedBlobs(); - - if (cursorProfileEnabled) sendEmptyCursorBundle(); - if (objectProfileEnabled) sendEmptyObjectBundle(); - if (blobProfileEnabled) sendEmptyBlobBundle(); - - delete []oscBuffer; - delete oscPacket; - delete []fullBuffer; - delete fullPacket; - - if (source_name) delete[] source_name; - for (unsigned int i=0;iisLocal()) && (senderList.size()==1)) { - setSourceName(source_name); - }*/ - - // resize packets to smallest transport method - unsigned int size = sender->getBufferSize(); - if (sizeCapacity()) { - osc::OutboundPacketStream *temp = oscPacket; - oscPacket = new osc::OutboundPacketStream(oscBuffer,size); - delete temp; - temp = fullPacket; - fullPacket = new osc::OutboundPacketStream(oscBuffer,size); - delete temp; - - } - - senderList.push_back(sender); -} - -void TuioServer::deliverOscPacket(osc::OutboundPacketStream *packet) { - - for (unsigned int i=0;isendOscPacket(packet); -} - -void TuioServer::setSourceName(const char *name, const char *ip) { - if (!source_name) source_name = new char[256]; - sprintf(source_name,"%s@%s",name,ip); -} - - -void TuioServer::setSourceName(const char *src) { - - if (!source_name) source_name = new char[256]; - - /*if (senderList[0]->isLocal()) { - sprintf(source_name,"%s",src); - } else {*/ - char hostname[64]; - char *source_addr = NULL; - struct hostent *hp = NULL; - struct in_addr *addr = NULL; - - gethostname(hostname, 64); - hp = gethostbyname(hostname); - - if (hp==NULL) { - sprintf(hostname, "%s.local", hostname); - hp = gethostbyname(hostname); - } - - if (hp!=NULL) { - for (int i = 0; hp->h_addr_list[i] != 0; ++i) { - addr = (struct in_addr *)(hp->h_addr_list[i]); - //std::cout << inet_ntoa(*addr) << std::endl; - source_addr = inet_ntoa(*addr); - } - } else { - //generate a random internet address - srand ( (unsigned int)time(NULL) ); - int32 r = rand(); - addr = (struct in_addr*)&r; - source_addr = inet_ntoa(*addr); - } - sprintf(source_name,"%s@%s",src,source_addr); - //} - - std::cout << "tuio/src " << source_name << std::endl; -} - -void TuioServer::commitFrame() { - TuioManager::commitFrame(); - - if(updateObject) { - startObjectBundle(); - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { - - // start a new packet if we exceed the packet capacity - if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addObjectMessage(tobj); - } - objectUpdateTime = TuioTime(currentFrameTime); - sendObjectBundle(currentFrame); - } else if (objectProfileEnabled && periodic_update) { - - TuioTime timeCheck = currentFrameTime - objectUpdateTime; - if(timeCheck.getSeconds()>=update_interval) { - objectUpdateTime = TuioTime(currentFrameTime); - startObjectBundle(); - if (full_update) { - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { - // start a new packet if we exceed the packet capacity - if ((oscPacket->Capacity()-oscPacket->Size())::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { - - // start a new packet if we exceed the packet capacity - if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addCursorMessage(tcur); - } - cursorUpdateTime = TuioTime(currentFrameTime); - sendCursorBundle(currentFrame); - } else if (cursorProfileEnabled && periodic_update) { - TuioTime timeCheck = currentFrameTime - cursorUpdateTime; - if(timeCheck.getSeconds()>=update_interval) { - cursorUpdateTime = TuioTime(currentFrameTime); - startCursorBundle(); - if (full_update) { - for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { - // start a new packet if we exceed the packet capacity - if ((oscPacket->Capacity()-oscPacket->Size())::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { - // start a new packet if we exceed the packet capacity - if ((oscPacket->Capacity()-oscPacket->Size())getTuioTime()==currentFrameTime)) addBlobMessage(tblb); - } - blobUpdateTime = TuioTime(currentFrameTime); - sendBlobBundle(currentFrame); - } else if (blobProfileEnabled && periodic_update) { - TuioTime timeCheck = currentFrameTime - blobUpdateTime; - if(timeCheck.getSeconds()>=update_interval) { - blobUpdateTime = TuioTime(currentFrameTime); - startBlobBundle(); - if (full_update) { - for (std::list::iterator tuioBlob =blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { - - // start a new packet if we exceed the packet capacity - if ((oscPacket->Capacity()-oscPacket->Size())Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive" << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage; - (*oscPacket) << osc::EndBundle; - deliverOscPacket( oscPacket ); -} - -void TuioServer::startCursorBundle() { - oscPacket->Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; - for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { - if ((*tuioCursor)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioCursor)->getSessionID()); - } - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::addCursorMessage(TuioCursor *tcur) { - - if (tcur->getTuioState()==TUIO_ADDED) return; - - float xpos = tcur->getX(); - float xvel = tcur->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = tcur->getY(); - float yvel = tcur->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - - (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set"; - (*oscPacket) << (int32)(tcur->getSessionID()) << xpos << ypos; - (*oscPacket) << xvel << yvel << tcur->getMotionAccel(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::sendCursorBundle(long fseq) { - (*oscPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << (int32)fseq << osc::EndMessage; - (*oscPacket) << osc::EndBundle; - deliverOscPacket( oscPacket ); -} - -void TuioServer::sendEmptyObjectBundle() { - oscPacket->Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive" << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage; - (*oscPacket) << osc::EndBundle; - deliverOscPacket( oscPacket ); -} - -void TuioServer::startObjectBundle() { - oscPacket->Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { - (*oscPacket) << (int32)((*tuioObject)->getSessionID()); - } - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::addObjectMessage(TuioObject *tobj) { - - float xpos = tobj->getX(); - float xvel = tobj->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = tobj->getY(); - float yvel = tobj->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - float angle = tobj->getAngle(); - float rvel = tobj->getRotationSpeed(); - if (invert_a) { - angle = 2.0f*(float)M_PI - angle; - rvel = -1 * rvel; - } - - (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set"; - (*oscPacket) << (int32)(tobj->getSessionID()) << tobj->getSymbolID() << xpos << ypos << angle; - (*oscPacket) << xvel << yvel << rvel << tobj->getMotionAccel() << tobj->getRotationAccel(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::sendObjectBundle(long fseq) { - (*oscPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << (int32)fseq << osc::EndMessage; - (*oscPacket) << osc::EndBundle; - deliverOscPacket( oscPacket ); -} - - -void TuioServer::sendEmptyBlobBundle() { - oscPacket->Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive" << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage; - (*oscPacket) << osc::EndBundle; - deliverOscPacket( oscPacket ); -} - -void TuioServer::startBlobBundle() { - oscPacket->Clear(); - (*oscPacket) << osc::BeginBundleImmediate; - if (source_name) (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; - (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; - for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { - if ((*tuioBlob)->getTuioState()!=TUIO_ADDED) (*oscPacket) << (int32)((*tuioBlob)->getSessionID()); - } - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::addBlobMessage(TuioBlob *tblb) { - - if (tblb->getTuioState()==TUIO_ADDED) return; - - float xpos = tblb->getX(); - float xvel = tblb->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = tblb->getY(); - float yvel = tblb->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - float angle = tblb->getAngle(); - float rvel = tblb->getRotationSpeed(); - if (invert_a) { - angle = 2.0f*(float)M_PI - angle; - rvel = -1 * rvel; - } - - (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set"; - (*oscPacket) << (int32)(tblb->getSessionID()) << xpos << ypos << angle << tblb->getWidth() << tblb->getHeight() << tblb->getArea(); - (*oscPacket) << xvel << yvel << rvel << tblb->getMotionAccel() << tblb->getRotationAccel(); - (*oscPacket) << osc::EndMessage; -} - -void TuioServer::sendBlobBundle(long fseq) { - (*oscPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << (int32)fseq << osc::EndMessage; - (*oscPacket) << osc::EndBundle; - - deliverOscPacket( oscPacket ); -} - -void TuioServer::sendFullMessages() { - - // prepare the cursor packet - fullPacket->Clear(); - (*fullPacket) << osc::BeginBundleImmediate; - if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; - // add the cursor alive message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; - for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) - (*fullPacket) << (int32)((*tuioCursor)->getSessionID()); - (*fullPacket) << osc::EndMessage; - - // add all current cursor set messages - for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) { - - // start a new packet if we exceed the packet capacity - if ((fullPacket->Capacity()-fullPacket->Size())Clear(); - (*fullPacket) << osc::BeginBundleImmediate; - if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "source" << source_name << osc::EndMessage; - // add the cursor alive message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "alive"; - for (std::list::iterator tuioCursor = cursorList.begin(); tuioCursor!=cursorList.end(); tuioCursor++) - (*fullPacket) << (int32)((*tuioCursor)->getSessionID()); - (*fullPacket) << osc::EndMessage; - } - - float xpos = (*tuioCursor)->getX(); - float xvel = (*tuioCursor)->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = (*tuioCursor)->getY(); - float yvel = (*tuioCursor)->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - - // add the actual cursor set message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "set"; - (*fullPacket) << (int32)((*tuioCursor)->getSessionID()) << xpos << ypos; - (*fullPacket) << xvel << yvel <<(*tuioCursor)->getMotionAccel(); - (*fullPacket) << osc::EndMessage; - } - - // add the immediate fseq message and send the cursor packet - (*fullPacket) << osc::BeginMessage( "/tuio/2Dcur") << "fseq" << -1 << osc::EndMessage; - (*fullPacket) << osc::EndBundle; - deliverOscPacket( fullPacket ); - - // prepare the object packet - fullPacket->Clear(); - (*fullPacket) << osc::BeginBundleImmediate; - if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; - // add the object alive message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) - (*fullPacket) << (int32)((*tuioObject)->getSessionID()); - (*fullPacket) << osc::EndMessage; - - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) { - - // start a new packet if we exceed the packet capacity - if ((fullPacket->Capacity()-fullPacket->Size())Clear(); - (*fullPacket) << osc::BeginBundleImmediate; - if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "source" << source_name << osc::EndMessage; - // add the object alive message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "alive"; - for (std::list::iterator tuioObject = objectList.begin(); tuioObject!=objectList.end(); tuioObject++) - (*fullPacket) << (int32)((*tuioObject)->getSessionID()); - (*fullPacket) << osc::EndMessage; - } - - float xpos = (*tuioObject)->getX(); - float xvel = (*tuioObject)->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = (*tuioObject)->getY(); - float yvel = (*tuioObject)->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - float angle = (*tuioObject)->getAngle(); - float rvel = (*tuioObject)->getRotationSpeed(); - if (invert_a) { - angle = 2.0f*(float)M_PI - angle; - rvel = -1 * rvel; - } - - // add the actual object set message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "set"; - (*fullPacket) << (int32)((*tuioObject)->getSessionID()) << (*tuioObject)->getSymbolID() << xpos << ypos << angle; - (*fullPacket) << xvel << yvel << rvel << (*tuioObject)->getMotionAccel() << (*tuioObject)->getRotationAccel(); - (*fullPacket) << osc::EndMessage; - - } - // add the immediate fseq message and send the object packet - (*fullPacket) << osc::BeginMessage( "/tuio/2Dobj") << "fseq" << -1 << osc::EndMessage; - (*fullPacket) << osc::EndBundle; - deliverOscPacket( fullPacket ); - - // prepare the blob packet - fullPacket->Clear(); - (*fullPacket) << osc::BeginBundleImmediate; - if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; - // add the object alive message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; - for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) - (*fullPacket) << (int32)((*tuioBlob)->getSessionID()); - (*fullPacket) << osc::EndMessage; - - for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) { - - // start a new packet if we exceed the packet capacity - if ((fullPacket->Capacity()-fullPacket->Size())Clear(); - (*fullPacket) << osc::BeginBundleImmediate; - if (source_name) (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "source" << source_name << osc::EndMessage; - // add the blob alive message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "alive"; - for (std::list::iterator tuioBlob = blobList.begin(); tuioBlob!=blobList.end(); tuioBlob++) - (*fullPacket) << (int32)((*tuioBlob)->getSessionID()); - (*fullPacket) << osc::EndMessage; - } - - float xpos = (*tuioBlob)->getX(); - float xvel = (*tuioBlob)->getXSpeed(); - if (invert_x) { - xpos = 1 - xpos; - xvel = -1 * xvel; - } - float ypos = (*tuioBlob)->getY(); - float yvel = (*tuioBlob)->getYSpeed(); - if (invert_y) { - ypos = 1 - ypos; - yvel = -1 * yvel; - } - float angle = (*tuioBlob)->getAngle(); - float rvel = (*tuioBlob)->getRotationSpeed(); - if (invert_a) { - angle = 2.0f*(float)M_PI - angle; - rvel = -1 * rvel; - } - - // add the actual blob set message - (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "set"; - (*fullPacket) << (int32)((*tuioBlob)->getSessionID()) << xpos << ypos << angle << (*tuioBlob)->getWidth() << (*tuioBlob)->getHeight() << (*tuioBlob)->getArea(); - (*fullPacket) << xvel << yvel << rvel << (*tuioBlob)->getMotionAccel() << (*tuioBlob)->getRotationAccel(); - (*fullPacket) << osc::EndMessage; - - } - // add the immediate fseq message and send the blob packet - (*fullPacket) << osc::BeginMessage( "/tuio/2Dblb") << "fseq" << -1 << osc::EndMessage; - (*fullPacket) << osc::EndBundle; - deliverOscPacket( fullPacket ); -} - - - diff --git a/modules/touch/ext/libTUIO/TUIO/TuioServer.h b/modules/touch/ext/libTUIO/TUIO/TuioServer.h deleted file mode 100644 index 66ad0a574f..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioServer.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TuioServer_H -#define INCLUDED_TuioServer_H - -#include "TuioManager.h" -#include "UdpSender.h" -#include "TcpSender.h" -#include "WebSockSender.h" -#include "FlashSender.h" -#include -#include -#include -#ifndef WIN32 -#include -#include -#include -#endif - -namespace TUIO { - /** - *

The TuioServer class is the central TUIO protocol encoder component. - * In order to encode and send TUIO messages an instance of TuioServer needs to be created. The TuioServer instance then generates TUIO messages - * which are deliverered by the provided OSCSender. The shown UDPSender send OSC to UDP port 3333 on localhost or to the configured host and port.

- *

During runtime the each frame is marked with the initFrame and commitFrame methods, - * while the currently present TuioObjects are managed by the server with ADD, UPDATE and REMOVE methods in analogy to the TuioClient's TuioListener interface.

- *

See the SimpleSimulator example project for further hints on how to use the TuioServer class and its various methods. - *

- * OscSender *sender = new UDPSender();
- * TuioServer *server = new TuioServer(sender);
- * server->setSourceName("MyTuioSource"); // optional for TUIO 1.1
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * TuioObject *tobj = server->addTuioObject(xpos,ypos,angle);
- * TuioCursor *tcur = server->addTuiCursor(xpos,ypos);
- * TuioBlob *tblb = server->addTuioBlob(xpos,ypos,angle,width,height, area);
- * server->commitFrame();
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * server->updateTuioObject(tobj,xpos,ypos,angle);
- * server->updateTuioCursor(tcur,xpos,ypos);
- * server->updateTuioBlob(tblb,xpos,ypos,angle,width,height,area);
- * server->commitFrame();
- * ...
- * server->initFrame(TuioTime::getSessionTime());
- * server->removeTuioObject(tobj);
- * server->removeTuioCursor(tcur);
- * server->removeTuioBlob(tblb);
- * server->commitFrame();
- *

- * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioServer : public TuioManager { - - public: - - /** - * This constructor creates a TuioServer that uses an internal UdpSender delivering the OSC data via UDP port 3333 on localhost - */ - TuioServer(); - - /** - * This constructor creates a TuioServer that uses an internal UdpSender delivering the OSC data via the provided UDP port on the provided host - * - * @param host the host name for UDP deleivery - * @param port the UDP port number on the provided host - */ - TuioServer(const char *host, int port); - - /** - * This constructor creates a TuioServer that sends OSC data using the provided OscSender - * - * @param sender the OscSender used for OSC data delivery - */ - TuioServer(OscSender *sender); - - /** - * The destructor is doing nothing in particular. - */ - ~TuioServer(); - - /** - * Generates and sends TUIO messages of all currently active TuioObjects, TuioCursors and TuioBlobs - */ - void sendFullMessages(); - - /** - * Enables the full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs - * - */ - void enableFullUpdate() { - full_update = true; - } - - /** - * Disables the full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs - */ - void disableFullUpdate() { - full_update = false; - } - - /** - * Returns true if the full update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled. - * @return true if the full update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled - */ - bool fullUpdateEnabled() { - return full_update; - } - - /** - * Disables the periodic full update of all currently active TuioObjects TuioObjects, TuioCursors and TuioBlobs - * - * @param interval update interval in seconds, defaults to one second - */ - void enablePeriodicMessages(int interval=1) { - periodic_update = true; - update_interval = interval; - } - - /** - * Disables the periodic full update of all currently active and inactive TuioObjects, TuioCursors and TuioBlobs - */ - void disablePeriodicMessages() { - periodic_update = false; - } - - /** - * Returns true if the periodic update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled. - * @return true if the periodic update of all currently active TuioObjects, TuioCursors and TuioBlobs is enabled - */ - bool periodicMessagesEnabled() { - return periodic_update; - } - - /** - * Returns the periodic update interval in seconds. - * @return the periodic update interval in seconds - */ - int getUpdateInterval() { - return update_interval; - } - - /** - * Commits the current frame. - * Generates and sends TUIO messages of all currently active and updated TuioObjects, TuioCursors and TuioBlobs. - */ - void commitFrame(); - - /** - * Commits the current frame. - * Generates and sends TUIO messages of all currently active and updated TuioObjects, TuioCursors and TuioBlobs. - */ - - /** - * Defines the name of this TUIO source, which is transmitted within the /tuio/[profile] source message. - * - * @param name the desired name of this TUIO source - */ - void setSourceName(const char *name); - - - /** - * Defines the name and IP address of this TUIO source, which is transmitted within the /tuio/[profile] source message. - * - * @param name the desired name of this TUIO source - * @param ip the local IP address - */ - void setSourceName(const char *name, const char *ip); - - - - void addOscSender(OscSender *sender); - - void enableObjectProfile(bool flag) { objectProfileEnabled = flag; }; - void enableCursorProfile(bool flag) { cursorProfileEnabled = flag; }; - void enableBlobProfile(bool flag) { blobProfileEnabled = flag; }; - - private: - - void initialize(OscSender *oscsend); - - std::vector senderList; - void deliverOscPacket(osc::OutboundPacketStream *packet); - - osc::OutboundPacketStream *oscPacket; - char *oscBuffer; - osc::OutboundPacketStream *fullPacket; - char *fullBuffer; - - void startObjectBundle(); - void addObjectMessage(TuioObject *tobj); - void sendObjectBundle(long fseq); - void sendEmptyObjectBundle(); - - void startCursorBundle(); - void addCursorMessage(TuioCursor *tcur); - void sendCursorBundle(long fseq); - void sendEmptyCursorBundle(); - - void startBlobBundle(); - void addBlobMessage(TuioBlob *tblb); - void sendBlobBundle(long fseq); - void sendEmptyBlobBundle(); - - int update_interval; - bool full_update, periodic_update; - TuioTime objectUpdateTime, cursorUpdateTime, blobUpdateTime ; - bool objectProfileEnabled, cursorProfileEnabled, blobProfileEnabled; - char *source_name; - }; -} -#endif /* INCLUDED_TuioServer_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/TuioTime.cpp b/modules/touch/ext/libTUIO/TUIO/TuioTime.cpp deleted file mode 100644 index f169c1451f..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioTime.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "TuioTime.h" -using namespace TUIO; - -long TuioTime::start_seconds = 0; -long TuioTime::start_micro_seconds = 0; - -TuioTime::TuioTime (long msec) { - seconds = msec/MSEC_SECOND; - micro_seconds = USEC_MILLISECOND*(msec%MSEC_SECOND); -} - -TuioTime::TuioTime (long sec, long usec) { - seconds = sec; - micro_seconds = usec; -} - -TuioTime TuioTime::operator+(long us) { - long sec = seconds + us/USEC_SECOND; - long usec = micro_seconds + us%USEC_SECOND; - return TuioTime(sec,usec); -} - -TuioTime TuioTime::operator+(TuioTime ttime) { - long sec = seconds + ttime.getSeconds(); - long usec = micro_seconds + ttime.getMicroseconds(); - sec += usec/USEC_SECOND; - usec = usec%USEC_SECOND; - return TuioTime(sec,usec); -} - -TuioTime TuioTime::operator-(long us) { - long sec = seconds - us/USEC_SECOND; - long usec = micro_seconds - us%USEC_SECOND; - - if (usec<0) { - usec += USEC_SECOND; - sec--; - } - - return TuioTime(sec,usec); -} - -TuioTime TuioTime::operator-(TuioTime ttime) { - long sec = seconds - ttime.getSeconds(); - long usec = micro_seconds - ttime.getMicroseconds(); - - if (usec<0) { - usec += USEC_SECOND; - sec--; - } - - return TuioTime(sec,usec); -} - -void TuioTime::operator=(TuioTime ttime) { - seconds = ttime.getSeconds(); - micro_seconds = ttime.getMicroseconds(); -} - -bool TuioTime::operator==(TuioTime ttime) { - if ((seconds==(long)ttime.getSeconds()) && (micro_seconds==(long)ttime.getMicroseconds())) return true; - else return false; -} - -bool TuioTime::operator!=(TuioTime ttime) { - if ((seconds!=(long)ttime.getSeconds()) || (micro_seconds!=(long)ttime.getMicroseconds())) return true; - else return false; -} - -void TuioTime::reset() { - seconds = 0; - micro_seconds = 0; -} - -long TuioTime::getSeconds() const{ - return seconds; -} - -long TuioTime::getMicroseconds() const{ - return micro_seconds; -} - -long TuioTime::getTotalMilliseconds() const{ - return seconds*MSEC_SECOND+micro_seconds/MSEC_SECOND; -} - -void TuioTime::initSession() { - TuioTime startTime = TuioTime::getSystemTime(); - start_seconds = startTime.getSeconds(); - start_micro_seconds = startTime.getMicroseconds(); -} - -TuioTime TuioTime::getSessionTime() { - return (getSystemTime() - getStartTime()); -} - -TuioTime TuioTime::getStartTime() { - return TuioTime(start_seconds,start_micro_seconds); -} - -TuioTime TuioTime::getSystemTime() { -#ifdef WIN32 - TuioTime systemTime(GetTickCount()); -#else - struct timeval tv; - struct timezone tz; - gettimeofday(&tv,&tz); - TuioTime systemTime(tv.tv_sec,tv.tv_usec); -#endif - return systemTime; -} diff --git a/modules/touch/ext/libTUIO/TUIO/TuioTime.h b/modules/touch/ext/libTUIO/TUIO/TuioTime.h deleted file mode 100644 index 567c443fc1..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/TuioTime.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_TUIOTIME_H -#define INCLUDED_TUIOTIME_H - -#include "LibExport.h" - -#ifndef WIN32 -#include -#include -#else -#include -#include -#endif - -#define MSEC_SECOND 1000 -#define USEC_SECOND 1000000 -#define USEC_MILLISECOND 1000 - -namespace TUIO { - - /** - * The TuioTime class is a simple structure that is used to reprent the time that has elapsed since the session start. - * The time is internally represented as seconds and fractions of microseconds which should be more than sufficient for gesture related timing requirements. - * Therefore at the beginning of a typical TUIO session the static method initSession() will set the reference time for the session. - * Another important static method getSessionTime will return a TuioTime object representing the time elapsed since the session start. - * The class also provides various addtional convience method, which allow some simple time arithmetics. - * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL TuioTime { - - private: - long seconds; - long micro_seconds; - static long start_seconds; - static long start_micro_seconds; - - public: - - /** - * The default constructor takes no arguments and sets - * the Seconds and Microseconds attributes of the newly created TuioTime both to zero. - */ - TuioTime ():seconds(0),micro_seconds(0) {}; - - /** - * The destructor is doing nothing in particular. - */ - ~TuioTime() {} - - /** - * This constructor takes the provided time represented in total Milliseconds - * and assigs this value to the newly created TuioTime. - * - * @param msec the total time in Millseconds - */ - TuioTime (long msec); - - /** - * This constructor takes the provided time represented in Seconds and Microseconds - * and assigs these value to the newly created TuioTime. - * - * @param sec the total time in seconds - * @param usec the microseconds time component - */ - TuioTime (long sec, long usec); - - /** - * Sums the provided time value represented in total Microseconds to this TuioTime. - * - * @param us the total time to add in Microseconds - * @return the sum of this TuioTime with the provided argument in microseconds - */ - TuioTime operator+(long us); - - /** - * Sums the provided TuioTime to the private Seconds and Microseconds attributes. - * - * @param ttime the TuioTime to add - * @return the sum of this TuioTime with the provided TuioTime argument - */ - TuioTime operator+(TuioTime ttime); - - /** - * Subtracts the provided time represented in Microseconds from the private Seconds and Microseconds attributes. - * - * @param us the total time to subtract in Microseconds - * @return the subtraction result of this TuioTime minus the provided time in Microseconds - */ - TuioTime operator-(long us); - - /** - * Subtracts the provided TuioTime from the private Seconds and Microseconds attributes. - * - * @param ttime the TuioTime to subtract - * @return the subtraction result of this TuioTime minus the provided TuioTime - */ - TuioTime operator-(TuioTime ttime); - - - /** - * Assigns the provided TuioTime to the private Seconds and Microseconds attributes. - * - * @param ttime the TuioTime to assign - */ - void operator=(TuioTime ttime); - - /** - * Takes a TuioTime argument and compares the provided TuioTime to the private Seconds and Microseconds attributes. - * - * @param ttime the TuioTime to compare - * @return true if the two TuioTime have equal Seconds and Microseconds attributes - */ - bool operator==(TuioTime ttime); - - /** - * Takes a TuioTime argument and compares the provided TuioTime to the private Seconds and Microseconds attributes. - * - * @param ttime the TuioTime to compare - * @return true if the two TuioTime have differnt Seconds or Microseconds attributes - */ - bool operator!=(TuioTime ttime); - - /** - * Resets the seconds and micro_seconds attributes to zero. - */ - void reset(); - - /** - * Returns the TuioTime Seconds component. - * @return the TuioTime Seconds component - */ - long getSeconds() const; - - /** - * Returns the TuioTime Microseconds component. - * @return the TuioTime Microseconds component - */ - long getMicroseconds() const; - - /** - * Returns the total TuioTime in Milliseconds. - * @return the total TuioTime in Milliseconds - */ - long getTotalMilliseconds() const; - - /** - * This static method globally resets the TUIO session time. - */ - static void initSession(); - - /** - * Returns the present TuioTime representing the time since session start. - * @return the present TuioTime representing the time since session start - */ - static TuioTime getSessionTime(); - - /** - * Returns the absolut TuioTime representing the session start. - * @return the absolut TuioTime representing the session start - */ - static TuioTime getStartTime(); - - /** - * Returns the absolut TuioTime representing the current system time. - * @return the absolut TuioTime representing the current system time - */ - static TuioTime getSystemTime(); - }; -} -#endif /* INCLUDED_TUIOTIME_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/UdpReceiver.cpp b/modules/touch/ext/libTUIO/TUIO/UdpReceiver.cpp deleted file mode 100644 index 38abac60ba..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/UdpReceiver.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "UdpReceiver.h" - -using namespace TUIO; -using namespace osc; - -#ifndef WIN32 -static void* ClientThreadFunc( void* obj ) -#else -static DWORD WINAPI ClientThreadFunc( LPVOID obj ) -#endif -{ - static_cast(obj)->socket->Run(); - return 0; -}; - -UdpReceiver::UdpReceiver(int port):locked (false) { - try { - socket = new UdpListeningReceiveSocket(IpEndpointName( IpEndpointName::ANY_ADDRESS, port ), this ); - } catch (std::exception &e) { - std::cerr << "could not bind to UDP port " << port << std::endl; - socket = NULL; - } - - if (socket!=NULL) { - if (!socket->IsBound()) { - delete socket; - socket = NULL; - } else std::cout << "listening to TUIO/UDP messages on port " << port << std::endl; - } -} - -UdpReceiver::~UdpReceiver() { - delete socket; -} - -void UdpReceiver::connect(bool lk) { - - if (connected) return; - if (socket==NULL) return; - locked = lk; - - if (!locked) { -#ifndef WIN32 - pthread_create(&thread , NULL, ClientThreadFunc, this); -#else - DWORD threadId; - thread = CreateThread( 0, 0, ClientThreadFunc, this, 0, &threadId ); -#endif - } else socket->Run(); - - connected = true; -} - -void UdpReceiver::disconnect() { - - if (!connected) return; - if (socket==NULL) { - connected = false; - locked = false; - return; - } - socket->Break(); - - if (!locked) { -#ifdef WIN32 - if( thread ) CloseHandle( thread ); -#endif - thread = 0; - } else locked = false; - - connected = false; -} - - diff --git a/modules/touch/ext/libTUIO/TUIO/UdpReceiver.h b/modules/touch/ext/libTUIO/TUIO/UdpReceiver.h deleted file mode 100644 index 9d29b4255f..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/UdpReceiver.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_UDPRECEIVER_H -#define INCLUDED_UDPRECEIVER_H - -#include "OscReceiver.h" -#include "oscpack/ip/UdpSocket.h" - -namespace TUIO { - - /** - * The UdpReceiver provides the OscReceiver functionality for the UDP transport method - * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL UdpReceiver: public OscReceiver { - - public: - - /** - * The UDP socket is only public to be accessible from the thread function - */ - UdpListeningReceiveSocket *socket; - - /** - * This constructor creates a UdpReceiver instance listening to the provided UDP port - * - * @param port the number of the UDP port to listen to, defaults to 3333 - */ - UdpReceiver (int port=3333); - - /** - * The destructor is doing nothing in particular. - */ - virtual ~UdpReceiver(); - - /** - * The UdpReceiver connects and starts receiving TUIO messages via UDP - * - * @param lock running in the background if set to false (default) - */ - void connect(bool lock=false); - - /** - * The UdpReceiver disconnects and stops receiving TUIO messages via UDP - */ - void disconnect(); - - private: - -#ifndef WIN32 - pthread_t thread; -#else - HANDLE thread; -#endif - - bool locked; - }; -}; -#endif /* INCLUDED_UDPRECEIVER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/UdpSender.cpp b/modules/touch/ext/libTUIO/TUIO/UdpSender.cpp deleted file mode 100644 index c4f8c109d9..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/UdpSender.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "UdpSender.h" - -using namespace TUIO; - -UdpSender::UdpSender() { - try { - local = true; - long unsigned int ip = GetHostByName("localhost"); - socket = new UdpTransmitSocket(IpEndpointName(ip, 3333)); - buffer_size = MAX_UDP_SIZE; - std::cout << "TUIO/UDP messages to " << "127.0.0.1@3333" << std::endl; - } catch (std::exception &e) { - std::cout << "could not create UDP socket" << std::endl; - socket = NULL; - throw std::exception(); - } -} - -UdpSender::UdpSender(const char *host, int port) { - try { - if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) { - local = true; - buffer_size = MAX_UDP_SIZE; - } else { - local = false; - buffer_size = IP_MTU_SIZE; - } - long unsigned int ip = GetHostByName(host); - socket = new UdpTransmitSocket(IpEndpointName(ip, port)); - std::cout << "TUIO/UDP messages to " << host << "@" << port << std::endl; - } catch (std::exception &e) { - std::cout << "could not create UDP socket" << std::endl; - socket = NULL; - throw std::exception(); - } -} - -UdpSender::UdpSender(const char *host, int port, int size) { - try { - if ((strcmp(host,"127.0.0.1")==0) || (strcmp(host,"localhost")==0)) { - local = true; - } else local = false; - long unsigned int ip = GetHostByName(host); - socket = new UdpTransmitSocket(IpEndpointName(ip, port)); - if (buffer_size>MAX_UDP_SIZE) buffer_size = MAX_UDP_SIZE; - else if (buffer_sizeSize() > buffer_size ) return false; - if ( bundle->Size() == 0 ) return false; - - socket->Send( bundle->Data(), bundle->Size() ); - return true; -} diff --git a/modules/touch/ext/libTUIO/TUIO/UdpSender.h b/modules/touch/ext/libTUIO/TUIO/UdpSender.h deleted file mode 100644 index 20927309c6..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/UdpSender.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2005-2016 Martin Kaltenbrunner - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_UDPSENDER_H -#define INCLUDED_UDPSENDER_H - -#include "OscSender.h" -#include "oscpack/ip/UdpSocket.h" - -#define IP_MTU_SIZE 1500 -#define MAX_UDP_SIZE 4096 -#define MIN_UDP_SIZE 576 - -namespace TUIO { - - /** - * The UdpSender implements the UDP transport method for OSC - * - * @author Martin Kaltenbrunner - * @version 1.1.6 - */ - class LIBDECL UdpSender : public OscSender { - - public: - - /** - * The default constructor creates a UdpSender that sends to the default UDP port 3333 on localhost - * using the maximum packet size of 65536 bytes for single packets on the loopback device - */ - UdpSender(); - - /** - * This constructor creates a UdpSender that sends to the provided port on the the given host - * using the default MTU size of 1500 bytes to deliver unfragmented UDP packets on a LAN - * - * @param host the receiving host name - * @param port the outgoing UDP port number - */ - - UdpSender(const char *host, int port); - /** - * This constructor creates a UdpSender that sends to the provided port on the the given host - * the UDP packet size can be set to a value between 576 and 65536 bytes - * - * @param host the receiving host name - * @param port the outgoing UDP port number - * @param size the maximum UDP packet size - */ - UdpSender(const char *host, int port, int size); - - /** - * The destructor closes the socket. - */ - virtual ~UdpSender(); - - /** - * This method delivers the provided OSC data - * - * @param *bundle the OSC stream to deliver - * @return true if the data was delivered successfully - */ - - bool sendOscPacket (osc::OutboundPacketStream *bundle); - - /** - * This method returns the connection state - * - * @return true if the connection is alive - */ - bool isConnected (); - - const char* tuio_type() { return "TUIO/UDP"; } - - private: - UdpTransmitSocket *socket; - }; -} -#endif /* INCLUDED_UDPSENDER_H */ diff --git a/modules/touch/ext/libTUIO/TUIO/WebSockSender.cpp b/modules/touch/ext/libTUIO/TUIO/WebSockSender.cpp deleted file mode 100644 index 3f4375fa78..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/WebSockSender.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2009-2016 Martin Kaltenbrunner - WebSockSender (c) 2015 Florian Echtler - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#include "WebSockSender.h" - -#ifdef WIN32 -#if not - defined int32_t - typedef DWORD int32_t; -#endif -#endif - -using namespace TUIO; - -WebSockSender::WebSockSender() - :TcpSender( 8080 ) -{ - local = true; - buffer_size = MAX_TCP_SIZE; - port_no = 8080; -} - -WebSockSender::WebSockSender(int port) - :TcpSender( port ) -{ - local = true; - buffer_size = MAX_TCP_SIZE; - port_no = port; -} - -bool WebSockSender::sendOscPacket (osc::OutboundPacketStream *bundle) { - if (!connected) return false; - if ( bundle->Size() > buffer_size ) return false; - if ( bundle->Size() == 0 ) return false; - -#ifdef OSC_HOST_LITTLE_ENDIAN - data_size[0] = bundle->Size()>>24; - data_size[1] = (bundle->Size()>>16) & 255; - data_size[2] = (bundle->Size()>>8) & 255; - data_size[3] = (bundle->Size()) & 255; -#else - *((int32_t*)data_size) = bundle->Size(); -#endif - -#ifdef WIN32 - std::list::iterator client; -#else - std::list::iterator client; -#endif - - for (client = tcp_client_list.begin(); client!=tcp_client_list.end(); client++) { - int len = bundle->Size(); - // add WebSocket header on top - uint8_t header[4] = { - 0x82, - (uint8_t)( len & 0xFF), - (uint8_t)((len >>8) & 0xFF), - (uint8_t)( len & 0xFF) - }; - int hs = 2; - if (len > 125) { hs = 4; header[1] = 126; } - memcpy(&data_buffer[0], &header, hs); - memcpy(&data_buffer[hs], bundle->Data(), bundle->Size()); - send((*client),data_buffer, hs+bundle->Size(),0); - } - - return true; -} - -void WebSockSender::newClient( int tcp_client ) { - - // socket -> file descriptor -#ifdef WIN32 - FILE* conn = _fdopen( tcp_client, "r+" ); -#else - FILE* conn = fdopen( tcp_client, "r+" ); -#endif - - // websocket challenge-response - uint8_t digest[SHA1_HASH_SIZE]; - char buf[1024] = "..."; - char key[1024]; - - // read client handshake challenge - while ((buf[0] != 0) && (buf[0] != '\r')) { - fgets( buf, sizeof(buf), conn ); - if (strncmp(buf,"Sec-WebSocket-Key: ",19) == 0) { - strncpy(key,buf+19,sizeof(key)); - key[strlen(buf)-21] = 0; - break; - } - } - - strncat(key,"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",sizeof(key)-strlen(key)-1); - sha1(digest,(uint8_t*)key,strlen(key)); - - snprintf(buf, sizeof(buf), - "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Access-Control-Allow-Origin: *\r\n" - "Sec-WebSocket-Accept: %s\r\n\r\n", - base64( digest, SHA1_HASH_SIZE ).c_str() ); - - send(tcp_client,buf, strlen(buf),0); -} - - -/* - * Incredibly minimal implementation of SHA1. - * Totally independent of any other code (even libc) so it can be - * run on bare hardware. - * - * Copyright (C) 2009 John Stumpo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY JOHN STUMPO ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL JOHN STUMPO BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -void WebSockSender::sha1( uint8_t digest[SHA1_HASH_SIZE], const uint8_t* inbuf, size_t length) { - - size_t i, j; - int remaining_bytes; - uint32_t h0, h1, h2, h3, h4, a, b, c, d, e, temp; - uint32_t w[80]; - unsigned char buf[64]; - - /* Initialize SHA1 hash state. */ - h0 = 0x67452301; - h1 = 0xefcdab89; - h2 = 0x98badcfe; - h3 = 0x10325476; - h4 = 0xc3d2e1f0; - - /* The extra 9 bytes are the pad byte (0x80) and 64-bit bit count that - are appended to the data being hashed. (There will more than likely - also be some zeroes in between the 0x80 and the bit count so that we - operate on a multiple of 64 bytes; 9 bytes, though, is the minimal - amount of extra data.) */ - for (i = 0; i < length + 9; i += 64) { - - /* Perform any padding necessary. */ - remaining_bytes = length - i; - if (remaining_bytes >= 64) { - memcpy(buf, inbuf + i, 64); - } else if (remaining_bytes >= 0) { - memcpy(buf, inbuf + i, remaining_bytes); - memset(buf + remaining_bytes, 0, 64 - remaining_bytes); - buf[remaining_bytes] = 0x80; - } else { - memset(buf, 0, 64); - } - - if (remaining_bytes < 56) - *(uint32_t*)(buf + 60) = SWAP(length * 8); - - /* Build the input array. */ - for (j = 0; j < 16; j++) - w[j] = SWAP(*(uint32_t*)(buf + j * 4)); - - for (j = 16; j < 80; j++) - w[j] = ROL(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); - - /* Load hash state. */ - a = h0; - b = h1; - c = h2; - d = h3; - e = h4; - - for (j = 0; j < 80; j++) { - - if (j < 20) - temp = ((b & c) | ((~b) & d)) + 0x5a827999; - else if (j < 40) - temp = (b ^ c ^ d) + 0x6ed9eba1; - else if (j < 60) - temp = ((b & c) | (b & d) | (c & d)) + 0x8f1bbcdc; - else - temp = (b ^ c ^ d) + 0xca62c1d6; - - temp += ROL(a, 5) + e + w[j]; - - e = d; - d = c; - c = ROR(b, 2); - b = a; - a = temp; - } - - /* Incorporate the results of the hash operation. */ - h0 += a; - h1 += b; - h2 += c; - h3 += d; - h4 += e; - } - - /* Write the hash into the output buffer. */ - *(uint32_t*)(digest) = SWAP(h0); - *(uint32_t*)(digest + 4) = SWAP(h1); - *(uint32_t*)(digest + 8) = SWAP(h2); - *(uint32_t*)(digest + 12) = SWAP(h3); - *(uint32_t*)(digest + 16) = SWAP(h4); -} - -/* - * a very simple base64 encoder, licensed as public domain. original source: - * https://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64 - */ - -const static unsigned char encodeLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -const static unsigned char padCharacter = '='; - -std::string WebSockSender::base64( uint8_t* cursor, size_t size ) { - - std::string encodedString; - uint32_t temp; - - encodedString.reserve(((size/3) + (size % 3 > 0)) * 4); - - for (size_t idx = 0; idx < size/3; idx++) { - - temp = (*cursor++) << 16; - temp += (*cursor++) << 8; - temp += (*cursor++); - - encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] ); - encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] ); - encodedString.append( 1, encodeLookup[(temp & 0x00000FC0) >> 6 ] ); - encodedString.append( 1, encodeLookup[(temp & 0x0000003F) ] ); - } - - switch (size % 3) { - case 1: - temp = (*cursor++) << 16; - encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] ); - encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] ); - encodedString.append( 2, padCharacter ); - break; - case 2: - temp = (*cursor++) << 16; - temp += (*cursor++) << 8; - encodedString.append( 1, encodeLookup[(temp & 0x00FC0000) >> 18] ); - encodedString.append( 1, encodeLookup[(temp & 0x0003F000) >> 12] ); - encodedString.append( 1, encodeLookup[(temp & 0x00000FC0) >> 6 ] ); - encodedString.append( 1, padCharacter); - break; - } - - return encodedString; -} - - diff --git a/modules/touch/ext/libTUIO/TUIO/WebSockSender.h b/modules/touch/ext/libTUIO/TUIO/WebSockSender.h deleted file mode 100644 index 968b07a333..0000000000 --- a/modules/touch/ext/libTUIO/TUIO/WebSockSender.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - TUIO C++ Library - Copyright (c) 2009-2016 Martin Kaltenbrunner - WebSockSender (c) 2015 Florian Echtler - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 3.0 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. -*/ - -#ifndef INCLUDED_WEBSOCKSENDER_H -#define INCLUDED_WEBSOCKSENDER_H - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#include -#include -#define snprintf c99_snprintf -#define vsnprintf c99_vsnprintf - -__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) -{ - int count = -1; - - if (size != 0) - count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); - if (count == -1) - count = _vscprintf(format, ap); - - return count; -} - -__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) -{ - int count; - va_list ap; - - va_start(ap, format); - count = c99_vsnprintf(outBuf, size, format, ap); - va_end(ap); - - return count; -} - -#endif - - -/* All of these macros assume use on a 32-bit variable. - Additionally, SWAP assumes we're little-endian. */ -#define SWAP(a) ((((a) >> 24) & 0x000000ff) | (((a) >> 8) & 0x0000ff00) | \ -(((a) << 8) & 0x00ff0000) | (((a) << 24) & 0xff000000)) -#define ROL(a, b) (((a) << (b)) | ((a) >> (32 - (b)))) -#define ROR(a, b) ROL((a), (32 - (b))) -#define SHA1_HASH_SIZE (160/8) - -#include "TcpSender.h" -#include -#include -#include -#include - -namespace TUIO { - - /** - * The WebSockSender implements the WebSocket transport method for OSC - * - * @author Florian Echtler - * @version 2.0.a0 - */ - class LIBDECL WebSockSender : public TcpSender { - - public: - - /** - * The default constructor creates a WebSockSender that listens to the default HTTP-alt port 8080 on localhost - */ - WebSockSender(); - - /** - * This constructor creates a WebSockSender that listens to the provided port - * - * @param port the listening WebSocket port number - */ - WebSockSender(int port); - - /** - * The destructor closes the socket. - */ - virtual ~WebSockSender() {} - - /** - * This method delivers the provided OSC data - * - * @param *bundle the OSC stream to deliver - * @return true if the data was delivered successfully - */ - bool sendOscPacket (osc::OutboundPacketStream *bundle); - - /** - * This method is called whenever a new client connects - * - * @param tcp_client the socket handle of the new client - */ - void newClient( int tcp_client ); - - const char* tuio_type() { return "TUIO/WEB"; } - private: - - void sha1( uint8_t digest[SHA1_HASH_SIZE], const uint8_t* inbuf, size_t length ); - std::string base64( uint8_t* buffer, size_t size ); - }; -} -#endif /* INCLUDED_WEBSOCKSENDER_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/CHANGES b/modules/touch/ext/libTUIO/oscpack/CHANGES deleted file mode 100644 index 5db666be36..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/CHANGES +++ /dev/null @@ -1,159 +0,0 @@ -April 9, 2013 -------------- - -Changes for the 1.1.0 release (vs 1.0.2) are listed below. Unless -otherwise indicated these changes have been made since -January 2013. The focus has been on general clean-up, fixing bugs, -compiler errors and warnings, and fixing issues on 64 bit platforms. -A few improvements such as support for OSC arrays, functions -for setting broadcast and reuse socket options have been added. -This update merges changes from the openFrameworks version -of oscpack. - - - Added support for arrays in messages (see OscUnitTests.cpp - for example usage). (patch thanks to Tim Blechmann) - - - Fixed bugs relating to 64 bit usage (e.g. crashes in 64 bit - builds on OS X). - - - Some member functions that previously used the "int" or - "unsigned long" type for parameters or return values now use - std::size_t (platform-defined) or - osc_bundle_element_size_t (a.k.a. int32). - This change was made to better support 64 bit platforms. - See SVN revision 70 for details. - - - The previous point introduces a breaking change on Linux/x86_64 - for callers of AsBlob() and AsBlobUnchecked(): - The type of the second argument (the "size" argument) to - ReceivedMessageArgument::AsBlob() and - ReceivedMessageArgument::AsBlobUnchecked() has changed - from unsigned long & to osc_bundle_element_size_t (an int32). - You should declare your size argument variables as - osc_bundle_element_size_t to avoid incompatibilities between - 32 and 64 bit builds. - - - Note that oscpack does not support packets larger than - 0x7FFFFFFC (see comments in class ReceivedPacket for - details). - - - Oscpack defines an osc::Nil value used for sending the nil - message argument value. This conflicts with Objective-C. - Therefore osc::Nil is no longer defined in Obj-C++ code. - There is now an osc::OscNil value, which should be preferred. - osc::Nil is still available when writing C++. - (fix thanks to openFrameworks) - - - Added UdpSocket::SetEnableBroadcast(). This needs to - be called to enable sending to the broadcast address on some - platforms (e.g. Mac OS X). (thanks to openFrameworks) - - - Added UdpSocket::SetAllowReuse(). This is useful for - sharing sockets on some platforms (Mac?), and not so useful - on other platforms. (thanks to openFrameworks) - - - Added IpEndpointName::IsMulticastAddress() (2010) - - - Cleaned up C++ header usage and std:: namespace usage - to be more standards compliant (fixes issues on recent compilers - such as clang and gcc4.6). - - - Improved host endianness detection. Should auto-detect - endianness on most platforms now. - (thanks to Tim Blechmann for help with this) - - - Fixed two memory leaks: (1) in OscPrintReceivedElements.cpp - when printing time tag message arguments (thanks to Gwydion ap Dafydd). - (2) in the posix SocketReceiveMultiplexer::Run() method if an exception - was thrown while listening. - - - Fixed bug in posix SocketReceiveMultiplexer::Run() that would cause - packets to stop being received if select() returned EINTR. - (thanks to Björn Wöldecke) - - - Updated and improved Makefile to avoid redundant re-linking - (thanks to Douglas Mandell) - - - Added CMakeLists.txt CMake build file (2010, thanks to David Doria) - - - Switched license to plain MIT license with non binding request - for contribution of improvements (same as current PortAudio - boilerplate). See LICENSE file. - -Thanks to Tim Blechmann, Rob Canning, Gwydion ap Dafydd, David Doria, -Christopher Delaney, Jon McCormack, Douglas Mandell, Björn Wöldecke, -all the guys at openFrameworks, and everyone who reported bugs, -submitted patches and helped out with testing this release. - -Thanks to Syneme at the University of Calgary for providing financial -support for the 1.1.0 update. - - -September 28, 2005 ------------------- - -Compared to the previous official snapshot (November 2004) the -current version of oscpack includes a re-written set of network -classes and some changes to the syntax of the networking code. It no -longer uses threads, which means that you don't need to use sleep() -if you are writing a simple single-threaded server, or you need to -spawn your own threads in a more complex application. - -The list below summarises the changes if you are porting code from -the previous release. - - - There are no longer any threads in oscpack. if you need to - set up an asynchronous listener you can create your own thread - and call Run on an instance of SocketReceiveMultiplexer or - UdpListeningReceiveSocket (see ip/UdpSocket.h) yourself. - - - Host byte order is now used for network (IP) addresses - - - Functions which used to take two parameters - now take an instance of IpEndpointName (see - ip/IpEndpointName.h) this class has a number of convenient - constructors for converting numbers and strings to internet - addresses. For example there is one which takes a string and - another that take the dotted address components as separate - parameters. - - - The UdpTransmitPort class, formerly in UdpTransmitPort.h, is - now called UdpTransmitSocket, which is simply a convenience - class derived from UdpSocket (see ip/UdpSocket.h). Where you - used to use the constructor UdpTransmitPort( address, port) now - you can use UdpTransmitSocket( IpEndpointName( address, port ) - ) or you can any of the other possible ctors to IpEndpointName - () (see above). The Send() method is unchanged. - - - The packet listener base class is now located in - ip/PacketListener.h instead of PacketListenerPort.h. The - ProcessPacket method now has an additional parameter indicating - the remote endpoint - - - The preferred way to set up listeners is with - SocketReceiveMultiplexer (in ip/UdpSocket.h), this also allows - attaching periodic timers. For simple applications which only - listen to a single socket with no timers you can use - UdpListeningReceiveSocket (also in UdpSocket.h) See - osc/OscReceiveTest.cpp or osc/OscDump.cpp for examples of this. - This is more or less equivalent to the UdpPacketListenerPort - object in the old oscpack versions except that you need to - explicitly call Run() before it will start receiving packets - and it runs in the same thread, not a separate thread so Run() - won't usually return. - - - Explicit calls to InitializeNetworking() and - TerminateNetworking() are no longer required for simple - applications (more complex windows applications should - instantiate NetworkInitializer in main() or WinMain (see - ip/NetworkingUtils.h/.cpp) - - - The OscPacketListener base class (OscPacketListener.h) was - added to make traversing OSC packets easier, it handles bundle - traversal automatically so you only need to process messages in - your derived classes. - - - On Windows be sure to link with ws2_32.lib or you will see - a linker error about WSAEventSelect not being found. Also you - will need to link with winmm.lib for timeGetTime() - diff --git a/modules/touch/ext/libTUIO/oscpack/LICENSE b/modules/touch/ext/libTUIO/oscpack/LICENSE deleted file mode 100644 index ebaaac1977..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/LICENSE +++ /dev/null @@ -1,34 +0,0 @@ -oscpack -- Open Sound Control (OSC) packet manipulation library -http://www.rossbencina.com/code/oscpack - -Copyright (c) 2004-2013 Ross Bencina - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files -(the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -### - -The text above constitutes the entire oscpack license; however, -the oscpack developer(s) also make the following non-binding requests: - -Any person wishing to distribute modifications to the Software is -requested to send the modifications to the original developer so that -they can be incorporated into the canonical version. It is also -requested that these non-binding requests be included whenever the -above license is reproduced. \ No newline at end of file diff --git a/modules/touch/ext/libTUIO/oscpack/README b/modules/touch/ext/libTUIO/oscpack/README deleted file mode 100644 index 5d1d5c1216..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/README +++ /dev/null @@ -1,150 +0,0 @@ -oscpack -- Open Sound Control packet manipulation library -A simple C++ library for packing and unpacking OSC packets. -http://www.rossbencina.com/code/oscpack - -Copyright (c) 2004-2013 Ross Bencina - - -Oscpack is simply a set of C++ classes for packing and unpacking OSC packets. -Oscpack includes a minimal set of UDP networking classes for Windows and POSIX. -The networking classes are sufficient for writing many OSC applications and servers, -but you are encouraged to use another networking framework if it better suits your needs. -Oscpack is not an OSC application framework. It doesn't include infrastructure for -constructing or routing OSC namespaces, just classes for easily constructing, -sending, receiving and parsing OSC packets. The library should also be easy to use -for other transport methods (e.g. serial). - -The key goals of the oscpack library are: - - - Be a simple and complete implementation of OSC - - Be portable to a wide variety of platforms - - Allow easy development of robust OSC applications - (for example it should be impossible to crash a server - by sending it malformed packets, and difficult to create - malformed packets.) - -Here's a quick run down of the key files: - -osc/OscReceivedElements -- classes for parsing a packet -osc/OscPrintRecievedElements -- iostream << operators for printing packet elements -osc/OscOutboundPacketStream -- a class for packing messages into a packet -osc/OscPacketListener -- base class for listening to OSC packets on a UdpSocket -ip/IpEndpointName -- class that represents an IP address and port number -ip/UdpSocket -- classes for UDP transmission and listening sockets -tests/OscUnitTests -- unit test program for the OSC modules -tests/OscSendTests -- examples of how to send messages -tests/OscReceiveTest -- example of how to receive the messages sent by OSCSendTests -examples/OscDump -- a program that prints received OSC packets -examples/SimpleSend -- a minimal program to send an OSC message -examples/SimpleReceive -- a minimal program to receive an OSC message - -osc/ contains all of the OSC related classes -ip/ contains the networking classes - -ip/windows contains the Windows implementation of the networking classes -ip/posix contains the POSIX implementation of the networking classes - - -Building --------- - -The idea is that you will embed this source code in your projects as you -see fit. The Makefile has an install rule for building a shared library and -installing headers in usr/local. It can also build a static library. -There is a CMakeLists.txt for building with cmake. - -Makefile builds -............... - -The Makefile works for Linux and Max OS X. It should also work on other platforms -that have make. Just run: - -$ make - -You can run "make install" if you like. - - -Cmake builds -............ - -There is a CMakeLists.txt file which has been tested with cmake on -Windows and Linux. It should work on other platforms too. -For example, to generate a Visual Studio 10 project, run cmake -like this: - -> cmake -G "Visual Studio 10" - -Run cmake without any parameters to get a list of available generators. - - -Mingw build batch file -...................... - -For Windows there is a batch file for doing a simple test build with -MinGW gcc called make.MinGW32.bat. This will build the test executables -and oscdump in ./bin and run the unit tests. - - -Note: - -In some rare instances you may need to edit the Makefile or -osc/OscHostEndianness.h to configure oscpack for the endianness of your -processor (see the comments at the top of the Makefile for details). - - - -Verification test ------------------ - -To run the unit tests: - -$ ./bin/OscUnitTests - -To run the send and receive tests. Open two terminals. In one run: - -$ ./bin/OscReceiveTest - -Then in the other terminal run: - -$./bin/OscSendTests - - -You should see an indication that the messages were received -in the first terminal. - -Note that OscSendTests intentionally sends some unexpected -message parameters to test exception handling in the receiver. -You will see some "error while parsing message" messages printed. - -You can use ./bin/OscDump to print out OSC messages received -from any program, including the test programs. - - --- - - -If you fix anything or write a set of TCP send/receive classes -please consider sending me a patch. My email address is -rossb@audiomulch.com. Thanks :) - -For more information about Open Sound Control, see: -http://opensoundcontrol.org/ - -Thanks to Till Bovermann for helping with POSIX networking code and -Mac compatibility, and to Martin Kaltenbrunner and the rest of the -reacTable team for giving me a reason to finish this library. Thanks -to Merlijn Blaauw for reviewing the interfaces. Thanks to Xavier Oliver -for additional help with Linux builds and POSIX implementation details. - -Portions developed at the Music Technology Group, Audiovisual Institute, -University Pompeu Fabra, Barcelona, during my stay as a visiting -researcher, November 2004 - September 2005. - -Thanks to Syneme at the University of Calgary for providing financial -support for the 1.1.0 update, December 2012 - March 2013. - -See the file CHANGES for information about recent updates. - -See the file LICENSE for information about distributing and using this code. - -### diff --git a/modules/touch/ext/libTUIO/oscpack/TODO b/modules/touch/ext/libTUIO/oscpack/TODO deleted file mode 100644 index 112f02eab5..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/TODO +++ /dev/null @@ -1,52 +0,0 @@ -TODO: - - - consider adding the local endpoint name to PacketListener::PacketReceived() params - - - consider adding ListenerThread class to support old seperate thread listener functionality, something like: - - class UdpSocketListenerThread{ - public: - UdpSocketListenerThread( UdpSocket& socket, Listener *listener ); - UdpSocketListenerThread( UdpSocketReceiveMultiplexer *mux ); - ~UdpSocketListenerThread(); - - void Run(); - void Stop(); - }; - - - work out a way to make the parsing classes totally safe. at a minimum this - means adding functions to test for invalid float/doublevalues, - making sure the iterators never pass the end of the message, ... - (passing end of message can happen if: - - too many args in type tags - a. typetags overflow message size - b. args fulfilling typetags overflow message size - - strings too long or not terminated correctly - - blobs too long or not terminated correctly - - if the message was fully checked during construction, the end() iterator - could be moved back until only arguments which fit withing size() may - be interated (this could be none). A flag could be set to indicate that - something was wrong. - - - other packet badness could include: - - time tags too far into the future (the scheduler should deal with - that i guess). - - message address patterns which aren't correctly terminated - - - improve the ability to parse messages without tags (SC uses methods which - get the data and advance the iterator in one step.) - - Check* could be modified to do this - ie if typetags are not present - it could check that reading the field won't escape the message size - and return the data, or return false if some consistency - constraint is violated. - (or alternately drop support for messages without type tags) - - - - add a method to discard an inprogress message if it gets half - constructed and the buffer is full in OutboundPacket - - - write a stress testing app which can send garbage packets to try to flush out other bugs in the parsing code. - - - diff --git a/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.cpp b/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.cpp deleted file mode 100644 index 50b0262216..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "IpEndpointName.h" - -#include - -#include "NetworkingUtils.h" - - -unsigned long IpEndpointName::GetHostByName( const char *s ) -{ - return ::GetHostByName(s); -} - - -void IpEndpointName::AddressAsString( char *s ) const -{ - if( address == ANY_ADDRESS ){ - std::sprintf( s, "" ); - }else{ - std::sprintf( s, "%d.%d.%d.%d", - (int)((address >> 24) & 0xFF), - (int)((address >> 16) & 0xFF), - (int)((address >> 8) & 0xFF), - (int)(address & 0xFF) ); - } -} - - -void IpEndpointName::AddressAndPortAsString( char *s ) const -{ - if( port == ANY_PORT ){ - if( address == ANY_ADDRESS ){ - std::sprintf( s, ":" ); - }else{ - std::sprintf( s, "%d.%d.%d.%d:", - (int)((address >> 24) & 0xFF), - (int)((address >> 16) & 0xFF), - (int)((address >> 8) & 0xFF), - (int)(address & 0xFF) ); - } - }else{ - if( address == ANY_ADDRESS ){ - std::sprintf( s, ":%d", port ); - }else{ - std::sprintf( s, "%d.%d.%d.%d:%d", - (int)((address >> 24) & 0xFF), - (int)((address >> 16) & 0xFF), - (int)((address >> 8) & 0xFF), - (int)(address & 0xFF), - (int)port ); - } - } -} diff --git a/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.h b/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.h deleted file mode 100644 index c83e1c3cfe..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/IpEndpointName.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_IPENDPOINTNAME_H -#define INCLUDED_OSCPACK_IPENDPOINTNAME_H - - -class IpEndpointName{ - static unsigned long GetHostByName( const char *s ); -public: - static const unsigned long ANY_ADDRESS = 0xFFFFFFFF; - static const int ANY_PORT = -1; - - IpEndpointName() - : address( ANY_ADDRESS ), port( ANY_PORT ) {} - IpEndpointName( int port_ ) - : address( ANY_ADDRESS ), port( port_ ) {} - IpEndpointName( unsigned long ipAddress_, int port_ ) - : address( ipAddress_ ), port( port_ ) {} - IpEndpointName( const char *addressName, int port_=ANY_PORT ) - : address( GetHostByName( addressName ) ) - , port( port_ ) {} - IpEndpointName( int addressA, int addressB, int addressC, int addressD, int port_=ANY_PORT ) - : address( ( (addressA << 24) | (addressB << 16) | (addressC << 8) | addressD ) ) - , port( port_ ) {} - - // address and port are maintained in host byte order here - unsigned long address; - int port; - - bool IsMulticastAddress() const { return ((address >> 24) & 0xFF) >= 224 && ((address >> 24) & 0xFF) <= 239; } - - enum { ADDRESS_STRING_LENGTH=17 }; - void AddressAsString( char *s ) const; - - enum { ADDRESS_AND_PORT_STRING_LENGTH=23}; - void AddressAndPortAsString( char *s ) const; -}; - -inline bool operator==( const IpEndpointName& lhs, const IpEndpointName& rhs ) -{ - return (lhs.address == rhs.address && lhs.port == rhs.port ); -} - -inline bool operator!=( const IpEndpointName& lhs, const IpEndpointName& rhs ) -{ - return !(lhs == rhs); -} - -#endif /* INCLUDED_OSCPACK_IPENDPOINTNAME_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/ip/NetworkingUtils.h b/modules/touch/ext/libTUIO/oscpack/ip/NetworkingUtils.h deleted file mode 100644 index a83612aeda..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/NetworkingUtils.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_NETWORKINGUTILS_H -#define INCLUDED_OSCPACK_NETWORKINGUTILS_H - - -// in general NetworkInitializer is only used internally, but if you're -// application creates multiple sockets from different threads at runtime you -// should instantiate one of these in main just to make sure the networking -// layer is initialized. -class NetworkInitializer{ -public: - NetworkInitializer(); - ~NetworkInitializer(); -}; - - -// return ip address of host name in host byte order -unsigned long GetHostByName( const char *name ); - - -#endif /* INCLUDED_OSCPACK_NETWORKINGUTILS_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/ip/PacketListener.h b/modules/touch/ext/libTUIO/oscpack/ip/PacketListener.h deleted file mode 100644 index 6c26b32996..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/PacketListener.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_PACKETLISTENER_H -#define INCLUDED_OSCPACK_PACKETLISTENER_H - - -class IpEndpointName; - -class PacketListener{ -public: - virtual ~PacketListener() {} - virtual void ProcessPacket( const char *data, int size, - const IpEndpointName& remoteEndpoint ) = 0; -}; - -#endif /* INCLUDED_OSCPACK_PACKETLISTENER_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/ip/TimerListener.h b/modules/touch/ext/libTUIO/oscpack/ip/TimerListener.h deleted file mode 100644 index 59b4040600..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/TimerListener.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_TIMERLISTENER_H -#define INCLUDED_OSCPACK_TIMERLISTENER_H - - -class TimerListener{ -public: - virtual ~TimerListener() {} - virtual void TimerExpired() = 0; -}; - -#endif /* INCLUDED_OSCPACK_TIMERLISTENER_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/ip/UdpSocket.h b/modules/touch/ext/libTUIO/oscpack/ip/UdpSocket.h deleted file mode 100644 index 2d7a189a1b..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/UdpSocket.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_UDPSOCKET_H -#define INCLUDED_OSCPACK_UDPSOCKET_H - -#include // size_t - -#include "NetworkingUtils.h" -#include "IpEndpointName.h" - - -class PacketListener; -class TimerListener; - -class UdpSocket; - -class SocketReceiveMultiplexer{ - class Implementation; - Implementation *impl_; - - friend class UdpSocket; - -public: - SocketReceiveMultiplexer(); - ~SocketReceiveMultiplexer(); - - // only call the attach/detach methods _before_ calling Run - - // only one listener per socket, each socket at most once - void AttachSocketListener( UdpSocket *socket, PacketListener *listener ); - void DetachSocketListener( UdpSocket *socket, PacketListener *listener ); - - void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ); - void AttachPeriodicTimerListener( - int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ); - void DetachPeriodicTimerListener( TimerListener *listener ); - - void Run(); // loop and block processing messages indefinitely - void RunUntilSigInt(); - void Break(); // call this from a listener to exit once the listener returns - void AsynchronousBreak(); // call this from another thread or signal handler to exit the Run() state -}; - - -class UdpSocket{ - class Implementation; - Implementation *impl_; - - friend class SocketReceiveMultiplexer::Implementation; - -public: - - // Ctor throws std::runtime_error if there's a problem - // initializing the socket. - UdpSocket(); - virtual ~UdpSocket(); - - // Enable broadcast addresses (e.g. x.x.x.255) - // Sets SO_BROADCAST socket option. - void SetEnableBroadcast( bool enableBroadcast ); - - // Enable multiple listeners for a single port on same - // network interface* - // Sets SO_REUSEADDR (also SO_REUSEPORT on OS X). - // [*] The exact behavior of SO_REUSEADDR and - // SO_REUSEPORT is undefined for some common cases - // and may have drastically different behavior on different - // operating systems. - void SetAllowReuse( bool allowReuse ); - - - // The socket is created in an unbound, unconnected state - // such a socket can only be used to send to an arbitrary - // address using SendTo(). To use Send() you need to first - // connect to a remote endpoint using Connect(). To use - // ReceiveFrom you need to first bind to a local endpoint - // using Bind(). - - // Retrieve the local endpoint name when sending to 'to' - IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const; - - // Connect to a remote endpoint which is used as the target - // for calls to Send() - void Connect( const IpEndpointName& remoteEndpoint ); - void Send( const char *data, std::size_t size ); - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ); - - - // Bind a local endpoint to receive incoming data. Endpoint - // can be 'any' for the system to choose an endpoint - void Bind( const IpEndpointName& localEndpoint ); - bool IsBound() const; - - std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ); -}; - - -// convenience classes for transmitting and receiving -// they just call Connect and/or Bind in the ctor. -// note that you can still use a receive socket -// for transmitting etc - -class UdpTransmitSocket : public UdpSocket{ -public: - UdpTransmitSocket( const IpEndpointName& remoteEndpoint ) - { Connect( remoteEndpoint ); } -}; - - -class UdpReceiveSocket : public UdpSocket{ -public: - UdpReceiveSocket( const IpEndpointName& localEndpoint ) - { Bind( localEndpoint ); } -}; - - -// UdpListeningReceiveSocket provides a simple way to bind one listener -// to a single socket without having to manually set up a SocketReceiveMultiplexer - -class UdpListeningReceiveSocket : public UdpSocket{ - SocketReceiveMultiplexer mux_; - PacketListener *listener_; -public: - UdpListeningReceiveSocket( const IpEndpointName& localEndpoint, PacketListener *listener ) - : listener_( listener ) - { - Bind( localEndpoint ); - mux_.AttachSocketListener( this, listener_ ); - } - - ~UdpListeningReceiveSocket() - { mux_.DetachSocketListener( this, listener_ ); } - - // see SocketReceiveMultiplexer above for the behaviour of these methods... - void Run() { mux_.Run(); } - void RunUntilSigInt() { mux_.RunUntilSigInt(); } - void Break() { mux_.Break(); } - void AsynchronousBreak() { mux_.AsynchronousBreak(); } -}; - - -#endif /* INCLUDED_OSCPACK_UDPSOCKET_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp b/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp deleted file mode 100644 index 720abc207e..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/posix/NetworkingUtils.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "oscpack/ip/NetworkingUtils.h" - -#include -#include -#include - -#include - - - -NetworkInitializer::NetworkInitializer() {} - -NetworkInitializer::~NetworkInitializer() {} - - -unsigned long GetHostByName( const char *name ) -{ - unsigned long result = 0; - - struct hostent *h = gethostbyname( name ); - if( h ){ - struct in_addr a; - std::memcpy( &a, h->h_addr_list[0], h->h_length ); - result = ntohl(a.s_addr); - } - - return result; -} diff --git a/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp b/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp deleted file mode 100644 index f0f1afbb78..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/posix/UdpSocket.cpp +++ /dev/null @@ -1,602 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "oscpack/ip/UdpSocket.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for sockaddr_in - -#include -#include -#include -#include - -#include -#include -#include // for memset -#include -#include - -#include "oscpack/ip/PacketListener.h" -#include "oscpack/ip/TimerListener.h" - - -#if defined(__APPLE__) && !defined(_SOCKLEN_T) -// pre system 10.3 didn't have socklen_t -typedef ssize_t socklen_t; -#endif - - -static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) -{ - std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); - sockAddr.sin_family = AF_INET; - - sockAddr.sin_addr.s_addr = - (endpoint.address == IpEndpointName::ANY_ADDRESS) - ? INADDR_ANY - : htonl( endpoint.address ); - - sockAddr.sin_port = - (endpoint.port == IpEndpointName::ANY_PORT) - ? 0 - : htons( endpoint.port ); -} - - -static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr ) -{ - return IpEndpointName( - (sockAddr.sin_addr.s_addr == INADDR_ANY) - ? IpEndpointName::ANY_ADDRESS - : ntohl( sockAddr.sin_addr.s_addr ), - (sockAddr.sin_port == 0) - ? IpEndpointName::ANY_PORT - : ntohs( sockAddr.sin_port ) - ); -} - - -class UdpSocket::Implementation{ - bool isBound_; - bool isConnected_; - - int socket_; - struct sockaddr_in connectedAddr_; - struct sockaddr_in sendToAddr_; - -public: - - Implementation() - : isBound_( false ) - , isConnected_( false ) - , socket_( -1 ) - { - if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == -1 ){ - throw std::runtime_error("unable to create udp socket\n"); - } - - std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); - sendToAddr_.sin_family = AF_INET; - } - - ~Implementation() - { - if (socket_ != -1) close(socket_); - } - - void SetEnableBroadcast( bool enableBroadcast ) - { - int broadcast = (enableBroadcast) ? 1 : 0; // int on posix - setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); - } - - void SetAllowReuse( bool allowReuse ) - { - int reuseAddr = (allowReuse) ? 1 : 0; // int on posix - setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); - -#ifdef __APPLE__ - // needed also for OS X - enable multiple listeners for a single port on same network interface - int reusePort = (allowReuse) ? 1 : 0; // int on posix - setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)); -#endif - } - - IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const - { - assert( isBound_ ); - - // first connect the socket to the remote server - - struct sockaddr_in connectSockAddr; - SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint ); - - if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) { - throw std::runtime_error("unable to connect udp socket\n"); - } - - // get the address - - struct sockaddr_in sockAddr; - std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); - socklen_t length = sizeof(sockAddr); - if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { - throw std::runtime_error("unable to getsockname\n"); - } - - if( isConnected_ ){ - // reconnect to the connected address - - if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { - throw std::runtime_error("unable to connect udp socket\n"); - } - - }else{ - // unconnect from the remote address - - struct sockaddr_in unconnectSockAddr; - std::memset( (char *)&unconnectSockAddr, 0, sizeof(unconnectSockAddr ) ); - unconnectSockAddr.sin_family = AF_UNSPEC; - // address fields are zero - int connectResult = connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)); - if ( connectResult < 0 && errno != EAFNOSUPPORT ) { - throw std::runtime_error("unable to un-connect udp socket\n"); - } - } - - return IpEndpointNameFromSockaddr( sockAddr ); - } - - void Connect( const IpEndpointName& remoteEndpoint ) - { - SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint ); - - if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { - throw std::runtime_error("unable to connect udp socket\n"); - } - - isConnected_ = true; - } - - void Send( const char *data, std::size_t size ) - { - assert( isConnected_ ); - - send( socket_, data, size, 0 ); - } - - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) - { - sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); - sendToAddr_.sin_port = htons( remoteEndpoint.port ); - - sendto( socket_, data, size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); - } - - void Bind( const IpEndpointName& localEndpoint ) - { - struct sockaddr_in bindSockAddr; - SockaddrFromIpEndpointName( bindSockAddr, localEndpoint ); - - if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) { - throw std::runtime_error("unable to bind udp socket\n"); - } - - isBound_ = true; - } - - bool IsBound() const { return isBound_; } - - std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) - { - assert( isBound_ ); - - struct sockaddr_in fromAddr; - socklen_t fromAddrLen = sizeof(fromAddr); - - ssize_t result = recvfrom(socket_, data, size, 0, - (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); - if( result < 0 ) - return 0; - - remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr); - remoteEndpoint.port = ntohs(fromAddr.sin_port); - - return (std::size_t)result; - } - - int Socket() { return socket_; } -}; - -UdpSocket::UdpSocket() -{ - impl_ = new Implementation(); -} - -UdpSocket::~UdpSocket() -{ - delete impl_; -} - -void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) -{ - impl_->SetEnableBroadcast( enableBroadcast ); -} - -void UdpSocket::SetAllowReuse( bool allowReuse ) -{ - impl_->SetAllowReuse( allowReuse ); -} - -IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const -{ - return impl_->LocalEndpointFor( remoteEndpoint ); -} - -void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) -{ - impl_->Connect( remoteEndpoint ); -} - -void UdpSocket::Send( const char *data, std::size_t size ) -{ - impl_->Send( data, size ); -} - -void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) -{ - impl_->SendTo( remoteEndpoint, data, size ); -} - -void UdpSocket::Bind( const IpEndpointName& localEndpoint ) -{ - impl_->Bind( localEndpoint ); -} - -bool UdpSocket::IsBound() const -{ - return impl_->IsBound(); -} - -std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) -{ - return impl_->ReceiveFrom( remoteEndpoint, data, size ); -} - - -struct AttachedTimerListener{ - AttachedTimerListener( int id, int p, TimerListener *tl ) - : initialDelayMs( id ) - , periodMs( p ) - , listener( tl ) {} - int initialDelayMs; - int periodMs; - TimerListener *listener; -}; - - -static bool CompareScheduledTimerCalls( - const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs ) -{ - return lhs.first < rhs.first; -} - - -SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0; - -extern "C" /*static*/ void InterruptSignalHandler( int ); -/*static*/ void InterruptSignalHandler( int ) -{ - multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak(); - signal( SIGINT, SIG_DFL ); -} - - -class SocketReceiveMultiplexer::Implementation{ - std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; - std::vector< AttachedTimerListener > timerListeners_; - - volatile bool break_; - int breakPipe_[2]; // [0] is the reader descriptor and [1] the writer - - double GetCurrentTimeMs() const - { - struct timeval t; - - gettimeofday( &t, 0 ); - - return ((double)t.tv_sec*1000.) + ((double)t.tv_usec / 1000.); - } - -public: - Implementation() - { - if( pipe(breakPipe_) != 0 ) - throw std::runtime_error( "creation of asynchronous break pipes failed\n" ); - } - - ~Implementation() - { - close( breakPipe_[0] ); - close( breakPipe_[1] ); - } - - void AttachSocketListener( UdpSocket *socket, PacketListener *listener ) - { - assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() ); - // we don't check that the same socket has been added multiple times, even though this is an error - socketListeners_.push_back( std::make_pair( listener, socket ) ); - } - - void DetachSocketListener( UdpSocket *socket, PacketListener *listener ) - { - std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = - std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ); - assert( i != socketListeners_.end() ); - - socketListeners_.erase( i ); - } - - void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) - { - timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) ); - } - - void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) - { - timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) ); - } - - void DetachPeriodicTimerListener( TimerListener *listener ) - { - std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); - while( i != timerListeners_.end() ){ - if( i->listener == listener ) - break; - ++i; - } - - assert( i != timerListeners_.end() ); - - timerListeners_.erase( i ); - } - - void Run() - { - break_ = false; - char *data = 0; - - try{ - - // configure the master fd_set for select() - - fd_set masterfds, tempfds; - FD_ZERO( &masterfds ); - FD_ZERO( &tempfds ); - - // in addition to listening to the inbound sockets we - // also listen to the asynchronous break pipe, so that AsynchronousBreak() - // can break us out of select() from another thread. - FD_SET( breakPipe_[0], &masterfds ); - int fdmax = breakPipe_[0]; - - for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); - i != socketListeners_.end(); ++i ){ - - if( fdmax < i->second->impl_->Socket() ) - fdmax = i->second->impl_->Socket(); - FD_SET( i->second->impl_->Socket(), &masterfds ); - } - - - // configure the timer queue - double currentTimeMs = GetCurrentTimeMs(); - - // expiry time ms, listener - std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; - for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); - i != timerListeners_.end(); ++i ) - timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); - std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); - - const int MAX_BUFFER_SIZE = 4098; - data = new char[ MAX_BUFFER_SIZE ]; - IpEndpointName remoteEndpoint; - - struct timeval timeout; - - while( !break_ ){ - tempfds = masterfds; - - struct timeval *timeoutPtr = 0; - if( !timerQueue_.empty() ){ - double timeoutMs = timerQueue_.front().first - GetCurrentTimeMs(); - if( timeoutMs < 0 ) - timeoutMs = 0; - - long timoutSecondsPart = (long)(timeoutMs * .001); - timeout.tv_sec = (time_t)timoutSecondsPart; - // 1000000 microseconds in a second - timeout.tv_usec = (suseconds_t)((timeoutMs - (timoutSecondsPart * 1000)) * 1000); - timeoutPtr = &timeout; - } - - if( select( fdmax + 1, &tempfds, 0, 0, timeoutPtr ) < 0 ){ - if( break_ ){ - break; - }else if( errno == EINTR ){ - // on returning an error, select() doesn't clear tempfds. - // so tempfds would remain all set, which would cause read( breakPipe_[0]... - // below to block indefinitely. therefore if select returns EINTR we restart - // the while() loop instead of continuing on to below. - continue; - }else{ - throw std::runtime_error("select failed\n"); - } - } - - if( FD_ISSET( breakPipe_[0], &tempfds ) ){ - // clear pending data from the asynchronous break pipe - char c; - read( breakPipe_[0], &c, 1 ); - } - - if( break_ ) - break; - - for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); - i != socketListeners_.end(); ++i ){ - - if( FD_ISSET( i->second->impl_->Socket(), &tempfds ) ){ - - std::size_t size = i->second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); - if( size > 0 ){ - i->first->ProcessPacket( data, (int)size, remoteEndpoint ); - if( break_ ) - break; - } - } - } - - // execute any expired timers - currentTimeMs = GetCurrentTimeMs(); - bool resort = false; - for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); - i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ - - i->second.listener->TimerExpired(); - if( break_ ) - break; - - i->first += i->second.periodMs; - resort = true; - } - if( resort ) - std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); - } - - delete [] data; - }catch(...){ - if( data ) - delete [] data; - throw; - } - } - - void Break() - { - break_ = true; - } - - void AsynchronousBreak() - { - break_ = true; - - // Send a termination message to the asynchronous break pipe, so select() will return - write( breakPipe_[1], "!", 1 ); - } -}; - - - -SocketReceiveMultiplexer::SocketReceiveMultiplexer() -{ - impl_ = new Implementation(); -} - -SocketReceiveMultiplexer::~SocketReceiveMultiplexer() -{ - delete impl_; -} - -void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener ) -{ - impl_->AttachSocketListener( socket, listener ); -} - -void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener ) -{ - impl_->DetachSocketListener( socket, listener ); -} - -void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) -{ - impl_->AttachPeriodicTimerListener( periodMilliseconds, listener ); -} - -void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) -{ - impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ); -} - -void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener ) -{ - impl_->DetachPeriodicTimerListener( listener ); -} - -void SocketReceiveMultiplexer::Run() -{ - impl_->Run(); -} - -void SocketReceiveMultiplexer::RunUntilSigInt() -{ - assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */ - multiplexerInstanceToAbortWithSigInt_ = this; - signal( SIGINT, InterruptSignalHandler ); - impl_->Run(); - signal( SIGINT, SIG_DFL ); - multiplexerInstanceToAbortWithSigInt_ = 0; -} - -void SocketReceiveMultiplexer::Break() -{ - impl_->Break(); -} - -void SocketReceiveMultiplexer::AsynchronousBreak() -{ - impl_->AsynchronousBreak(); -} - diff --git a/modules/touch/ext/libTUIO/oscpack/ip/win32/NetworkingUtils.cpp b/modules/touch/ext/libTUIO/oscpack/ip/win32/NetworkingUtils.cpp deleted file mode 100644 index 487cfa38a0..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/win32/NetworkingUtils.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "oscpack/ip/NetworkingUtils.h" - -#include // this must come first to prevent errors with MSVC7 -#include - -#include - - -static LONG initCount_ = 0; -static bool winsockInitialized_ = false; - -NetworkInitializer::NetworkInitializer() -{ - if( InterlockedIncrement( &initCount_ ) == 1 ){ - // there is a race condition here if one thread tries to access - // the library while another is still initializing it. - // i can't think of an easy way to fix it so i'm telling you here - // incase you need to init the library from two threads at once. - // this is why the header file advises to instantiate one of these - // in main() so that the initialization happens globally - - // initialize winsock - WSAData wsaData; - int nCode = WSAStartup(MAKEWORD(1, 1), &wsaData); - if( nCode != 0 ){ - //std::cout << "WSAStartup() failed with error code " << nCode << "\n"; - }else{ - winsockInitialized_ = true; - } - } -} - - -NetworkInitializer::~NetworkInitializer() -{ - if( InterlockedDecrement( &initCount_ ) == 0 ){ - if( winsockInitialized_ ){ - WSACleanup(); - winsockInitialized_ = false; - } - } -} - - -unsigned long GetHostByName( const char *name ) -{ - NetworkInitializer networkInitializer; - - unsigned long result = 0; - - struct hostent *h = gethostbyname( name ); - if( h ){ - struct in_addr a; - std::memcpy( &a, h->h_addr_list[0], h->h_length ); - result = ntohl(a.s_addr); - } - - return result; -} diff --git a/modules/touch/ext/libTUIO/oscpack/ip/win32/UdpSocket.cpp b/modules/touch/ext/libTUIO/oscpack/ip/win32/UdpSocket.cpp deleted file mode 100644 index 57cff3f5bf..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/ip/win32/UdpSocket.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ - -#include // this must come first to prevent errors with MSVC7 -#include -#include // for timeGetTime() - -#ifndef WINCE -#include -#endif - -#include -#include -#include // for memset -#include -#include - -#include "oscpack/ip/UdpSocket.h" // usually I'd include the module header first - // but this is causing conflicts with BCB4 due to - // std::size_t usage. - -#include "oscpack/ip/NetworkingUtils.h" -#include "oscpack/ip/PacketListener.h" -#include "oscpack/ip/TimerListener.h" - - -typedef int socklen_t; - - -static void SockaddrFromIpEndpointName( struct sockaddr_in& sockAddr, const IpEndpointName& endpoint ) -{ - std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); - sockAddr.sin_family = AF_INET; - - sockAddr.sin_addr.s_addr = - (endpoint.address == IpEndpointName::ANY_ADDRESS) - ? INADDR_ANY - : htonl( endpoint.address ); - - sockAddr.sin_port = - (endpoint.port == IpEndpointName::ANY_PORT) - ? (short)0 - : htons( (short)endpoint.port ); -} - - -static IpEndpointName IpEndpointNameFromSockaddr( const struct sockaddr_in& sockAddr ) -{ - return IpEndpointName( - (sockAddr.sin_addr.s_addr == INADDR_ANY) - ? IpEndpointName::ANY_ADDRESS - : ntohl( sockAddr.sin_addr.s_addr ), - (sockAddr.sin_port == 0) - ? IpEndpointName::ANY_PORT - : ntohs( sockAddr.sin_port ) - ); -} - - -class UdpSocket::Implementation{ - NetworkInitializer networkInitializer_; - - bool isBound_; - bool isConnected_; - - SOCKET socket_; - struct sockaddr_in connectedAddr_; - struct sockaddr_in sendToAddr_; - -public: - - Implementation() - : isBound_( false ) - , isConnected_( false ) - , socket_( INVALID_SOCKET ) - { - if( (socket_ = socket( AF_INET, SOCK_DGRAM, 0 )) == INVALID_SOCKET ){ - throw std::runtime_error("unable to create udp socket\n"); - } - - std::memset( &sendToAddr_, 0, sizeof(sendToAddr_) ); - sendToAddr_.sin_family = AF_INET; - } - - ~Implementation() - { - if (socket_ != INVALID_SOCKET) closesocket(socket_); - } - - void SetEnableBroadcast( bool enableBroadcast ) - { - char broadcast = (char)((enableBroadcast) ? 1 : 0); // char on win32 - setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); - } - - void SetAllowReuse( bool allowReuse ) - { - // Note: SO_REUSEADDR is non-deterministic for listening sockets on Win32. See MSDN article: - // "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" - // http://msdn.microsoft.com/en-us/library/ms740621%28VS.85%29.aspx - - char reuseAddr = (char)((allowReuse) ? 1 : 0); // char on win32 - setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)); - } - - IpEndpointName LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const - { - assert( isBound_ ); - - // first connect the socket to the remote server - - struct sockaddr_in connectSockAddr; - SockaddrFromIpEndpointName( connectSockAddr, remoteEndpoint ); - - if (connect(socket_, (struct sockaddr *)&connectSockAddr, sizeof(connectSockAddr)) < 0) { - throw std::runtime_error("unable to connect udp socket\n"); - } - - // get the address - - struct sockaddr_in sockAddr; - std::memset( (char *)&sockAddr, 0, sizeof(sockAddr ) ); - socklen_t length = sizeof(sockAddr); - if (getsockname(socket_, (struct sockaddr *)&sockAddr, &length) < 0) { - throw std::runtime_error("unable to getsockname\n"); - } - - if( isConnected_ ){ - // reconnect to the connected address - - if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { - throw std::runtime_error("unable to connect udp socket\n"); - } - - }else{ - // unconnect from the remote address - - struct sockaddr_in unconnectSockAddr; - SockaddrFromIpEndpointName( unconnectSockAddr, IpEndpointName() ); - - if( connect(socket_, (struct sockaddr *)&unconnectSockAddr, sizeof(unconnectSockAddr)) < 0 - && WSAGetLastError() != WSAEADDRNOTAVAIL ){ - throw std::runtime_error("unable to un-connect udp socket\n"); - } - } - - return IpEndpointNameFromSockaddr( sockAddr ); - } - - void Connect( const IpEndpointName& remoteEndpoint ) - { - SockaddrFromIpEndpointName( connectedAddr_, remoteEndpoint ); - - if (connect(socket_, (struct sockaddr *)&connectedAddr_, sizeof(connectedAddr_)) < 0) { - throw std::runtime_error("unable to connect udp socket\n"); - } - - isConnected_ = true; - } - - void Send( const char *data, std::size_t size ) - { - assert( isConnected_ ); - - send( socket_, data, (int)size, 0 ); - } - - void SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) - { - sendToAddr_.sin_addr.s_addr = htonl( remoteEndpoint.address ); - sendToAddr_.sin_port = htons( (short)remoteEndpoint.port ); - - sendto( socket_, data, (int)size, 0, (sockaddr*)&sendToAddr_, sizeof(sendToAddr_) ); - } - - void Bind( const IpEndpointName& localEndpoint ) - { - struct sockaddr_in bindSockAddr; - SockaddrFromIpEndpointName( bindSockAddr, localEndpoint ); - - if (bind(socket_, (struct sockaddr *)&bindSockAddr, sizeof(bindSockAddr)) < 0) { - throw std::runtime_error("unable to bind udp socket\n"); - } - - isBound_ = true; - } - - bool IsBound() const { return isBound_; } - - std::size_t ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) - { - assert( isBound_ ); - - struct sockaddr_in fromAddr; - socklen_t fromAddrLen = sizeof(fromAddr); - - int result = recvfrom(socket_, data, (int)size, 0, - (struct sockaddr *) &fromAddr, (socklen_t*)&fromAddrLen); - if( result < 0 ) - return 0; - - remoteEndpoint.address = ntohl(fromAddr.sin_addr.s_addr); - remoteEndpoint.port = ntohs(fromAddr.sin_port); - - return result; - } - - SOCKET& Socket() { return socket_; } -}; - -UdpSocket::UdpSocket() -{ - impl_ = new Implementation(); -} - -UdpSocket::~UdpSocket() -{ - delete impl_; -} - -void UdpSocket::SetEnableBroadcast( bool enableBroadcast ) -{ - impl_->SetEnableBroadcast( enableBroadcast ); -} - -void UdpSocket::SetAllowReuse( bool allowReuse ) -{ - impl_->SetAllowReuse( allowReuse ); -} - -IpEndpointName UdpSocket::LocalEndpointFor( const IpEndpointName& remoteEndpoint ) const -{ - return impl_->LocalEndpointFor( remoteEndpoint ); -} - -void UdpSocket::Connect( const IpEndpointName& remoteEndpoint ) -{ - impl_->Connect( remoteEndpoint ); -} - -void UdpSocket::Send( const char *data, std::size_t size ) -{ - impl_->Send( data, size ); -} - -void UdpSocket::SendTo( const IpEndpointName& remoteEndpoint, const char *data, std::size_t size ) -{ - impl_->SendTo( remoteEndpoint, data, size ); -} - -void UdpSocket::Bind( const IpEndpointName& localEndpoint ) -{ - impl_->Bind( localEndpoint ); -} - -bool UdpSocket::IsBound() const -{ - return impl_->IsBound(); -} - -std::size_t UdpSocket::ReceiveFrom( IpEndpointName& remoteEndpoint, char *data, std::size_t size ) -{ - return impl_->ReceiveFrom( remoteEndpoint, data, size ); -} - - -struct AttachedTimerListener{ - AttachedTimerListener( int id, int p, TimerListener *tl ) - : initialDelayMs( id ) - , periodMs( p ) - , listener( tl ) {} - int initialDelayMs; - int periodMs; - TimerListener *listener; -}; - - -static bool CompareScheduledTimerCalls( - const std::pair< double, AttachedTimerListener > & lhs, const std::pair< double, AttachedTimerListener > & rhs ) -{ - return lhs.first < rhs.first; -} - - -SocketReceiveMultiplexer *multiplexerInstanceToAbortWithSigInt_ = 0; - -extern "C" /*static*/ void InterruptSignalHandler( int ); -/*static*/ void InterruptSignalHandler( int ) -{ - multiplexerInstanceToAbortWithSigInt_->AsynchronousBreak(); -#ifndef WINCE - signal( SIGINT, SIG_DFL ); -#endif -} - - -class SocketReceiveMultiplexer::Implementation{ - NetworkInitializer networkInitializer_; - - std::vector< std::pair< PacketListener*, UdpSocket* > > socketListeners_; - std::vector< AttachedTimerListener > timerListeners_; - - volatile bool break_; - HANDLE breakEvent_; - - double GetCurrentTimeMs() const - { -#ifndef WINCE - return timeGetTime(); // FIXME: bad choice if you want to run for more than 40 days -#else - return 0; -#endif - } - -public: - Implementation() - { - breakEvent_ = CreateEvent( NULL, FALSE, FALSE, NULL ); - } - - ~Implementation() - { - CloseHandle( breakEvent_ ); - } - - void AttachSocketListener( UdpSocket *socket, PacketListener *listener ) - { - assert( std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ) == socketListeners_.end() ); - // we don't check that the same socket has been added multiple times, even though this is an error - socketListeners_.push_back( std::make_pair( listener, socket ) ); - } - - void DetachSocketListener( UdpSocket *socket, PacketListener *listener ) - { - std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = - std::find( socketListeners_.begin(), socketListeners_.end(), std::make_pair(listener, socket) ); - assert( i != socketListeners_.end() ); - - socketListeners_.erase( i ); - } - - void AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) - { - timerListeners_.push_back( AttachedTimerListener( periodMilliseconds, periodMilliseconds, listener ) ); - } - - void AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) - { - timerListeners_.push_back( AttachedTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ) ); - } - - void DetachPeriodicTimerListener( TimerListener *listener ) - { - std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); - while( i != timerListeners_.end() ){ - if( i->listener == listener ) - break; - ++i; - } - - assert( i != timerListeners_.end() ); - - timerListeners_.erase( i ); - } - - void Run() - { - break_ = false; - - // prepare the window events which we use to wake up on incoming data - // we use this instead of select() primarily to support the AsyncBreak() - // mechanism. - - std::vector events( socketListeners_.size() + 1, 0 ); - int j=0; - for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); - i != socketListeners_.end(); ++i, ++j ){ - - HANDLE event = CreateEvent( NULL, FALSE, FALSE, NULL ); - WSAEventSelect( i->second->impl_->Socket(), event, FD_READ ); // note that this makes the socket non-blocking which is why we can safely call RecieveFrom() on all sockets below - events[j] = event; - } - - - events[ socketListeners_.size() ] = breakEvent_; // last event in the collection is the break event - - - // configure the timer queue - double currentTimeMs = GetCurrentTimeMs(); - - // expiry time ms, listener - std::vector< std::pair< double, AttachedTimerListener > > timerQueue_; - for( std::vector< AttachedTimerListener >::iterator i = timerListeners_.begin(); - i != timerListeners_.end(); ++i ) - timerQueue_.push_back( std::make_pair( currentTimeMs + i->initialDelayMs, *i ) ); - std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); - - const int MAX_BUFFER_SIZE = 4098; - char *data = new char[ MAX_BUFFER_SIZE ]; - IpEndpointName remoteEndpoint; - - while( !break_ ){ - - double currentTimeMs = GetCurrentTimeMs(); - - DWORD waitTime = INFINITE; - if( !timerQueue_.empty() ){ - - waitTime = (DWORD)( timerQueue_.front().first >= currentTimeMs - ? timerQueue_.front().first - currentTimeMs - : 0 ); - } - - DWORD waitResult = WaitForMultipleObjects( (DWORD)socketListeners_.size() + 1, &events[0], FALSE, waitTime ); - if( break_ ) - break; - - if( waitResult != WAIT_TIMEOUT ){ - for( int i = waitResult - WAIT_OBJECT_0; i < (int)socketListeners_.size(); ++i ){ - std::size_t size = socketListeners_[i].second->ReceiveFrom( remoteEndpoint, data, MAX_BUFFER_SIZE ); - if( size > 0 ){ - socketListeners_[i].first->ProcessPacket( data, (int)size, remoteEndpoint ); - if( break_ ) - break; - } - } - } - - // execute any expired timers - currentTimeMs = GetCurrentTimeMs(); - bool resort = false; - for( std::vector< std::pair< double, AttachedTimerListener > >::iterator i = timerQueue_.begin(); - i != timerQueue_.end() && i->first <= currentTimeMs; ++i ){ - - i->second.listener->TimerExpired(); - if( break_ ) - break; - - i->first += i->second.periodMs; - resort = true; - } - if( resort ) - std::sort( timerQueue_.begin(), timerQueue_.end(), CompareScheduledTimerCalls ); - } - - delete [] data; - - // free events - j = 0; - for( std::vector< std::pair< PacketListener*, UdpSocket* > >::iterator i = socketListeners_.begin(); - i != socketListeners_.end(); ++i, ++j ){ - - WSAEventSelect( i->second->impl_->Socket(), events[j], 0 ); // remove association between socket and event - CloseHandle( events[j] ); - unsigned long enableNonblocking = 0; - ioctlsocket( i->second->impl_->Socket(), FIONBIO, &enableNonblocking ); // make the socket blocking again - } - } - - void Break() - { - break_ = true; - } - - void AsynchronousBreak() - { - break_ = true; - SetEvent( breakEvent_ ); - } -}; - - - -SocketReceiveMultiplexer::SocketReceiveMultiplexer() -{ - impl_ = new Implementation(); -} - -SocketReceiveMultiplexer::~SocketReceiveMultiplexer() -{ - delete impl_; -} - -void SocketReceiveMultiplexer::AttachSocketListener( UdpSocket *socket, PacketListener *listener ) -{ - impl_->AttachSocketListener( socket, listener ); -} - -void SocketReceiveMultiplexer::DetachSocketListener( UdpSocket *socket, PacketListener *listener ) -{ - impl_->DetachSocketListener( socket, listener ); -} - -void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int periodMilliseconds, TimerListener *listener ) -{ - impl_->AttachPeriodicTimerListener( periodMilliseconds, listener ); -} - -void SocketReceiveMultiplexer::AttachPeriodicTimerListener( int initialDelayMilliseconds, int periodMilliseconds, TimerListener *listener ) -{ - impl_->AttachPeriodicTimerListener( initialDelayMilliseconds, periodMilliseconds, listener ); -} - -void SocketReceiveMultiplexer::DetachPeriodicTimerListener( TimerListener *listener ) -{ - impl_->DetachPeriodicTimerListener( listener ); -} - -void SocketReceiveMultiplexer::Run() -{ - impl_->Run(); -} - -void SocketReceiveMultiplexer::RunUntilSigInt() -{ - assert( multiplexerInstanceToAbortWithSigInt_ == 0 ); /* at present we support only one multiplexer instance running until sig int */ - multiplexerInstanceToAbortWithSigInt_ = this; -#ifndef WINCE - signal( SIGINT, InterruptSignalHandler ); -#endif - impl_->Run(); -#ifndef WINCE - signal( SIGINT, SIG_DFL ); -#endif - multiplexerInstanceToAbortWithSigInt_ = 0; -} - -void SocketReceiveMultiplexer::Break() -{ - impl_->Break(); -} - -void SocketReceiveMultiplexer::AsynchronousBreak() -{ - impl_->AsynchronousBreak(); -} - diff --git a/modules/touch/ext/libTUIO/oscpack/osc/MessageMappingOscPacketListener.h b/modules/touch/ext/libTUIO/oscpack/osc/MessageMappingOscPacketListener.h deleted file mode 100644 index bf56b530a2..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/MessageMappingOscPacketListener.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H -#define INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H - -#include -#include - -#include "OscPacketListener.h" - - - -namespace osc{ - -template< class T > -class MessageMappingOscPacketListener : public OscPacketListener{ -public: - typedef void (T::*function_type)(const osc::ReceivedMessage&, const IpEndpointName&); - -protected: - void RegisterMessageFunction( const char *addressPattern, function_type f ) - { - functions_.insert( std::make_pair( addressPattern, f ) ); - } - - virtual void ProcessMessage( const osc::ReceivedMessage& m, - const IpEndpointName& remoteEndpoint ) - { - typename function_map_type::iterator i = functions_.find( m.AddressPattern() ); - if( i != functions_.end() ) - (dynamic_cast(this)->*(i->second))( m, remoteEndpoint ); - } - -private: - struct cstr_compare{ - bool operator()( const char *lhs, const char *rhs ) const - { return std::strcmp( lhs, rhs ) < 0; } - }; - - typedef std::map function_map_type; - function_map_type functions_; -}; - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_MESSAGEMAPPINGOSCPACKETLISTENER_H */ \ No newline at end of file diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscException.h b/modules/touch/ext/libTUIO/oscpack/osc/OscException.h deleted file mode 100644 index 73981737e0..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscException.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_OSCEXCEPTION_H -#define INCLUDED_OSCPACK_OSCEXCEPTION_H - -#include - -namespace osc{ - -class Exception : public std::exception { - const char *what_; - -public: - Exception() throw() {} - Exception( const Exception& src ) throw() - : std::exception( src ) - , what_( src.what_ ) {} - Exception( const char *w ) throw() - : what_( w ) {} - Exception& operator=( const Exception& src ) throw() - { what_ = src.what_; return *this; } - virtual ~Exception() throw() {} - virtual const char* what() const throw() { return what_; } -}; - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_OSCEXCEPTION_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscHostEndianness.h b/modules/touch/ext/libTUIO/oscpack/osc/OscHostEndianness.h deleted file mode 100644 index 4682c473a5..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscHostEndianness.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H -#define INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H - -/* - Make sure either OSC_HOST_LITTLE_ENDIAN or OSC_HOST_BIG_ENDIAN is defined - - We try to use preprocessor symbols to deduce the host endianness. - - Alternatively you can define one of the above symbols from the command line. - Usually you do this with the -D flag to the compiler. e.g.: - - $ g++ -DOSC_HOST_LITTLE_ENDIAN ... -*/ - -#if defined(OSC_HOST_LITTLE_ENDIAN) || defined(OSC_HOST_BIG_ENDIAN) - -// endianness defined on the command line. nothing to do here. - -#elif defined(__WIN32__) || defined(WIN32) || defined(WINCE) - -// assume that __WIN32__ is only defined on little endian systems - -#define OSC_HOST_LITTLE_ENDIAN 1 -#undef OSC_HOST_BIG_ENDIAN - -#elif defined(__APPLE__) - -#if defined(__LITTLE_ENDIAN__) - -#define OSC_HOST_LITTLE_ENDIAN 1 -#undef OSC_HOST_BIG_ENDIAN - -#elif defined(__BIG_ENDIAN__) - -#define OSC_HOST_BIG_ENDIAN 1 -#undef OSC_HOST_LITTLE_ENDIAN - -#endif - -#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) - -// should cover gcc and clang - -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - -#define OSC_HOST_LITTLE_ENDIAN 1 -#undef OSC_HOST_BIG_ENDIAN - -#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - -#define OSC_HOST_BIG_ENDIAN 1 -#undef OSC_HOST_LITTLE_ENDIAN - -#endif - -#else - -// gcc defines __LITTLE_ENDIAN__ and __BIG_ENDIAN__ -// for others used here see http://sourceforge.net/p/predef/wiki/Endianness/ -#if (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \ - || (defined(__ARMEL__) && !defined(__ARMEB__)) \ - || (defined(__AARCH64EL__) && !defined(__AARCH64EB__)) \ - || (defined(_MIPSEL) && !defined(_MIPSEB)) \ - || (defined(__MIPSEL) && !defined(__MIPSEB)) \ - || (defined(__MIPSEL__) && !defined(__MIPSEB__)) - -#define OSC_HOST_LITTLE_ENDIAN 1 -#undef OSC_HOST_BIG_ENDIAN - -#elif (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \ - || (defined(__ARMEB__) && !defined(__ARMEL__)) \ - || (defined(__AARCH64EB__) && !defined(__AARCH64EL__)) \ - || (defined(_MIPSEB) && !defined(_MIPSEL)) \ - || (defined(__MIPSEB) && !defined(__MIPSEL)) \ - || (defined(__MIPSEB__) && !defined(__MIPSEL__)) - -#define OSC_HOST_BIG_ENDIAN 1 -#undef OSC_HOST_LITTLE_ENDIAN - -#endif - -#endif - -#if !defined(OSC_HOST_LITTLE_ENDIAN) && !defined(OSC_HOST_BIG_ENDIAN) - -#error please edit OSCHostEndianness.h or define one of {OSC_HOST_LITTLE_ENDIAN, OSC_HOST_BIG_ENDIAN} to configure endianness - -#endif - -#endif /* INCLUDED_OSCPACK_OSCHOSTENDIANNESS_H */ - diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.cpp deleted file mode 100644 index b474b4f01a..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.cpp +++ /dev/null @@ -1,683 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "OscOutboundPacketStream.h" - -#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) -#include // for alloca -#else -//#include // alloca on Linux (also OSX) -#include // alloca on OSX and FreeBSD (and Linux?) -#endif - -#include -#include // memcpy, memmove, strcpy, strlen -#include // ptrdiff_t - -#include "OscHostEndianness.h" - -#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug -namespace std { -using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. -} -#endif - -namespace osc{ - -static void FromInt32( char *p, int32 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::int32 i; - char c[4]; - } u; - - u.i = x; - - p[3] = u.c[0]; - p[2] = u.c[1]; - p[1] = u.c[2]; - p[0] = u.c[3]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -static void FromUInt32( char *p, uint32 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::uint32 i; - char c[4]; - } u; - - u.i = x; - - p[3] = u.c[0]; - p[2] = u.c[1]; - p[1] = u.c[2]; - p[0] = u.c[3]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -static void FromInt64( char *p, int64 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::int64 i; - char c[8]; - } u; - - u.i = x; - - p[7] = u.c[0]; - p[6] = u.c[1]; - p[5] = u.c[2]; - p[4] = u.c[3]; - p[3] = u.c[4]; - p[2] = u.c[5]; - p[1] = u.c[6]; - p[0] = u.c[7]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -static void FromUInt64( char *p, uint64 x ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::uint64 i; - char c[8]; - } u; - - u.i = x; - - p[7] = u.c[0]; - p[6] = u.c[1]; - p[5] = u.c[2]; - p[4] = u.c[3]; - p[3] = u.c[4]; - p[2] = u.c[5]; - p[1] = u.c[6]; - p[0] = u.c[7]; -#else - *reinterpret_cast(p) = x; -#endif -} - - -// round up to the next highest multiple of 4. unless x is already a multiple of 4 -static inline std::size_t RoundUp4( std::size_t x ) -{ - return (x + 3) & ~((std::size_t)0x03); -} - - -OutboundPacketStream::OutboundPacketStream( char *buffer, std::size_t capacity ) - : data_( buffer ) - , end_( data_ + capacity ) - , typeTagsCurrent_( end_ ) - , messageCursor_( data_ ) - , argumentCurrent_( data_ ) - , elementSizePtr_( 0 ) - , messageIsInProgress_( false ) -{ - // sanity check integer types declared in OscTypes.h - // you'll need to fix OscTypes.h if any of these asserts fail - assert( sizeof(osc::int32) == 4 ); - assert( sizeof(osc::uint32) == 4 ); - assert( sizeof(osc::int64) == 8 ); - assert( sizeof(osc::uint64) == 8 ); -} - - -OutboundPacketStream::~OutboundPacketStream() -{ - -} - - -char *OutboundPacketStream::BeginElement( char *beginPtr ) -{ - if( elementSizePtr_ == 0 ){ - - elementSizePtr_ = reinterpret_cast(data_); - - return beginPtr; - - }else{ - // store an offset to the old element size ptr in the element size slot - // we store an offset rather than the actual pointer to be 64 bit clean. - *reinterpret_cast(beginPtr) = - (uint32)(reinterpret_cast(elementSizePtr_) - data_); - - elementSizePtr_ = reinterpret_cast(beginPtr); - - return beginPtr + 4; - } -} - - -void OutboundPacketStream::EndElement( char *endPtr ) -{ - assert( elementSizePtr_ != 0 ); - - if( elementSizePtr_ == reinterpret_cast(data_) ){ - - elementSizePtr_ = 0; - - }else{ - // while building an element, an offset to the containing element's - // size slot is stored in the elements size slot (or a ptr to data_ - // if there is no containing element). We retrieve that here - uint32 *previousElementSizePtr = - reinterpret_cast(data_ + *elementSizePtr_); - - // then we store the element size in the slot. note that the element - // size does not include the size slot, hence the - 4 below. - - std::ptrdiff_t d = endPtr - reinterpret_cast(elementSizePtr_); - // assert( d >= 4 && d <= 0x7FFFFFFF ); // assume packets smaller than 2Gb - - uint32 elementSize = static_cast(d - 4); - FromUInt32( reinterpret_cast(elementSizePtr_), elementSize ); - - // finally, we reset the element size ptr to the containing element - elementSizePtr_ = previousElementSizePtr; - } -} - - -bool OutboundPacketStream::ElementSizeSlotRequired() const -{ - return (elementSizePtr_ != 0); -} - - -void OutboundPacketStream::CheckForAvailableBundleSpace() -{ - std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) + 16; - - if( required > Capacity() ) - throw OutOfBufferMemoryException(); -} - - -void OutboundPacketStream::CheckForAvailableMessageSpace( const char *addressPattern ) -{ - // plus 4 for at least four bytes of type tag - std::size_t required = Size() + ((ElementSizeSlotRequired())?4:0) - + RoundUp4(std::strlen(addressPattern) + 1) + 4; - - if( required > Capacity() ) - throw OutOfBufferMemoryException(); -} - - -void OutboundPacketStream::CheckForAvailableArgumentSpace( std::size_t argumentLength ) -{ - // plus three for extra type tag, comma and null terminator - std::size_t required = (argumentCurrent_ - data_) + argumentLength - + RoundUp4( (end_ - typeTagsCurrent_) + 3 ); - - if( required > Capacity() ) - throw OutOfBufferMemoryException(); -} - - -void OutboundPacketStream::Clear() -{ - typeTagsCurrent_ = end_; - messageCursor_ = data_; - argumentCurrent_ = data_; - elementSizePtr_ = 0; - messageIsInProgress_ = false; -} - - -std::size_t OutboundPacketStream::Capacity() const -{ - return end_ - data_; -} - - -std::size_t OutboundPacketStream::Size() const -{ - std::size_t result = argumentCurrent_ - data_; - if( IsMessageInProgress() ){ - // account for the length of the type tag string. the total type tag - // includes an initial comma, plus at least one terminating \0 - result += RoundUp4( (end_ - typeTagsCurrent_) + 2 ); - } - - return result; -} - - -const char *OutboundPacketStream::Data() const -{ - return data_; -} - - -bool OutboundPacketStream::IsReady() const -{ - return (!IsMessageInProgress() && !IsBundleInProgress()); -} - - -bool OutboundPacketStream::IsMessageInProgress() const -{ - return messageIsInProgress_; -} - - -bool OutboundPacketStream::IsBundleInProgress() const -{ - return (elementSizePtr_ != 0); -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const BundleInitiator& rhs ) -{ - if( IsMessageInProgress() ) - throw MessageInProgressException(); - - CheckForAvailableBundleSpace(); - - messageCursor_ = BeginElement( messageCursor_ ); - - std::memcpy( messageCursor_, "#bundle\0", 8 ); - FromUInt64( messageCursor_ + 8, rhs.timeTag ); - - messageCursor_ += 16; - argumentCurrent_ = messageCursor_; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const BundleTerminator& rhs ) -{ - (void) rhs; - - if( !IsBundleInProgress() ) - throw BundleNotInProgressException(); - if( IsMessageInProgress() ) - throw MessageInProgressException(); - - EndElement( messageCursor_ ); - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const BeginMessage& rhs ) -{ - if( IsMessageInProgress() ) - throw MessageInProgressException(); - - CheckForAvailableMessageSpace( rhs.addressPattern ); - - messageCursor_ = BeginElement( messageCursor_ ); - - std::strcpy( messageCursor_, rhs.addressPattern ); - std::size_t rhsLength = std::strlen(rhs.addressPattern); - messageCursor_ += rhsLength + 1; - - // zero pad to 4-byte boundary - std::size_t i = rhsLength + 1; - while( i & 0x3 ){ - *messageCursor_++ = '\0'; - ++i; - } - - argumentCurrent_ = messageCursor_; - typeTagsCurrent_ = end_; - - messageIsInProgress_ = true; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const MessageTerminator& rhs ) -{ - (void) rhs; - - if( !IsMessageInProgress() ) - throw MessageNotInProgressException(); - - std::size_t typeTagsCount = end_ - typeTagsCurrent_; - - if( typeTagsCount ){ - - char *tempTypeTags = (char*)alloca(typeTagsCount); - std::memcpy( tempTypeTags, typeTagsCurrent_, typeTagsCount ); - - // slot size includes comma and null terminator - std::size_t typeTagSlotSize = RoundUp4( typeTagsCount + 2 ); - - std::size_t argumentsSize = argumentCurrent_ - messageCursor_; - - std::memmove( messageCursor_ + typeTagSlotSize, messageCursor_, argumentsSize ); - - messageCursor_[0] = ','; - // copy type tags in reverse (really forward) order - for( std::size_t i=0; i < typeTagsCount; ++i ) - messageCursor_[i+1] = tempTypeTags[ (typeTagsCount-1) - i ]; - - char *p = messageCursor_ + 1 + typeTagsCount; - for( std::size_t i=0; i < (typeTagSlotSize - (typeTagsCount + 1)); ++i ) - *p++ = '\0'; - - typeTagsCurrent_ = end_; - - // advance messageCursor_ for next message - messageCursor_ += typeTagSlotSize + argumentsSize; - - }else{ - // send an empty type tags string - std::memcpy( messageCursor_, ",\0\0\0", 4 ); - - // advance messageCursor_ for next message - messageCursor_ += 4; - } - - argumentCurrent_ = messageCursor_; - - EndElement( messageCursor_ ); - - messageIsInProgress_ = false; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( bool rhs ) -{ - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = (char)((rhs) ? TRUE_TYPE_TAG : FALSE_TYPE_TAG); - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const NilType& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = NIL_TYPE_TAG; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const InfinitumType& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = INFINITUM_TYPE_TAG; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( int32 rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = INT32_TYPE_TAG; - FromInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( float rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = FLOAT_TYPE_TAG; - -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - float f; - char c[4]; - } u; - - u.f = rhs; - - argumentCurrent_[3] = u.c[0]; - argumentCurrent_[2] = u.c[1]; - argumentCurrent_[1] = u.c[2]; - argumentCurrent_[0] = u.c[3]; -#else - *reinterpret_cast(argumentCurrent_) = rhs; -#endif - - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( char rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = CHAR_TYPE_TAG; - FromInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const RgbaColor& rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = RGBA_COLOR_TYPE_TAG; - FromUInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const MidiMessage& rhs ) -{ - CheckForAvailableArgumentSpace(4); - - *(--typeTagsCurrent_) = MIDI_MESSAGE_TYPE_TAG; - FromUInt32( argumentCurrent_, rhs ); - argumentCurrent_ += 4; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( int64 rhs ) -{ - CheckForAvailableArgumentSpace(8); - - *(--typeTagsCurrent_) = INT64_TYPE_TAG; - FromInt64( argumentCurrent_, rhs ); - argumentCurrent_ += 8; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const TimeTag& rhs ) -{ - CheckForAvailableArgumentSpace(8); - - *(--typeTagsCurrent_) = TIME_TAG_TYPE_TAG; - FromUInt64( argumentCurrent_, rhs ); - argumentCurrent_ += 8; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( double rhs ) -{ - CheckForAvailableArgumentSpace(8); - - *(--typeTagsCurrent_) = DOUBLE_TYPE_TAG; - -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - double f; - char c[8]; - } u; - - u.f = rhs; - - argumentCurrent_[7] = u.c[0]; - argumentCurrent_[6] = u.c[1]; - argumentCurrent_[5] = u.c[2]; - argumentCurrent_[4] = u.c[3]; - argumentCurrent_[3] = u.c[4]; - argumentCurrent_[2] = u.c[5]; - argumentCurrent_[1] = u.c[6]; - argumentCurrent_[0] = u.c[7]; -#else - *reinterpret_cast(argumentCurrent_) = rhs; -#endif - - argumentCurrent_ += 8; - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const char *rhs ) -{ - CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); - - *(--typeTagsCurrent_) = STRING_TYPE_TAG; - std::strcpy( argumentCurrent_, rhs ); - std::size_t rhsLength = std::strlen(rhs); - argumentCurrent_ += rhsLength + 1; - - // zero pad to 4-byte boundary - std::size_t i = rhsLength + 1; - while( i & 0x3 ){ - *argumentCurrent_++ = '\0'; - ++i; - } - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const Symbol& rhs ) -{ - CheckForAvailableArgumentSpace( RoundUp4(std::strlen(rhs) + 1) ); - - *(--typeTagsCurrent_) = SYMBOL_TYPE_TAG; - std::strcpy( argumentCurrent_, rhs ); - std::size_t rhsLength = std::strlen(rhs); - argumentCurrent_ += rhsLength + 1; - - // zero pad to 4-byte boundary - std::size_t i = rhsLength + 1; - while( i & 0x3 ){ - *argumentCurrent_++ = '\0'; - ++i; - } - - return *this; -} - - -OutboundPacketStream& OutboundPacketStream::operator<<( const Blob& rhs ) -{ - CheckForAvailableArgumentSpace( 4 + RoundUp4(rhs.size) ); - - *(--typeTagsCurrent_) = BLOB_TYPE_TAG; - FromUInt32( argumentCurrent_, rhs.size ); - argumentCurrent_ += 4; - - std::memcpy( argumentCurrent_, rhs.data, rhs.size ); - argumentCurrent_ += rhs.size; - - // zero pad to 4-byte boundary - unsigned long i = rhs.size; - while( i & 0x3 ){ - *argumentCurrent_++ = '\0'; - ++i; - } - - return *this; -} - -OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayInitiator& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = ARRAY_BEGIN_TYPE_TAG; - - return *this; -} - -OutboundPacketStream& OutboundPacketStream::operator<<( const ArrayTerminator& rhs ) -{ - (void) rhs; - CheckForAvailableArgumentSpace(0); - - *(--typeTagsCurrent_) = ARRAY_END_TYPE_TAG; - - return *this; -} - -} // namespace osc - - diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.h b/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.h deleted file mode 100644 index 1a90a01239..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscOutboundPacketStream.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H -#define INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H - -#include // size_t - -#include "OscTypes.h" -#include "OscException.h" - - -namespace osc{ - -class OutOfBufferMemoryException : public Exception{ -public: - OutOfBufferMemoryException( const char *w="out of buffer memory" ) - : Exception( w ) {} -}; - -class BundleNotInProgressException : public Exception{ -public: - BundleNotInProgressException( - const char *w="call to EndBundle when bundle is not in progress" ) - : Exception( w ) {} -}; - -class MessageInProgressException : public Exception{ -public: - MessageInProgressException( - const char *w="opening or closing bundle or message while message is in progress" ) - : Exception( w ) {} -}; - -class MessageNotInProgressException : public Exception{ -public: - MessageNotInProgressException( - const char *w="call to EndMessage when message is not in progress" ) - : Exception( w ) {} -}; - - -class OutboundPacketStream{ -public: - OutboundPacketStream( char *buffer, std::size_t capacity ); - ~OutboundPacketStream(); - - void Clear(); - - std::size_t Capacity() const; - - // invariant: size() is valid even while building a message. - std::size_t Size() const; - - const char *Data() const; - - // indicates that all messages have been closed with a matching EndMessage - // and all bundles have been closed with a matching EndBundle - bool IsReady() const; - - bool IsMessageInProgress() const; - bool IsBundleInProgress() const; - - OutboundPacketStream& operator<<( const BundleInitiator& rhs ); - OutboundPacketStream& operator<<( const BundleTerminator& rhs ); - - OutboundPacketStream& operator<<( const BeginMessage& rhs ); - OutboundPacketStream& operator<<( const MessageTerminator& rhs ); - - OutboundPacketStream& operator<<( bool rhs ); - OutboundPacketStream& operator<<( const NilType& rhs ); - OutboundPacketStream& operator<<( const InfinitumType& rhs ); - OutboundPacketStream& operator<<( int32 rhs ); - -#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)) - OutboundPacketStream& operator<<( int rhs ) - { *this << (int32)rhs; return *this; } -#endif - - OutboundPacketStream& operator<<( float rhs ); - OutboundPacketStream& operator<<( char rhs ); - OutboundPacketStream& operator<<( const RgbaColor& rhs ); - OutboundPacketStream& operator<<( const MidiMessage& rhs ); - OutboundPacketStream& operator<<( int64 rhs ); - OutboundPacketStream& operator<<( const TimeTag& rhs ); - OutboundPacketStream& operator<<( double rhs ); - OutboundPacketStream& operator<<( const char* rhs ); - OutboundPacketStream& operator<<( const Symbol& rhs ); - OutboundPacketStream& operator<<( const Blob& rhs ); - - OutboundPacketStream& operator<<( const ArrayInitiator& rhs ); - OutboundPacketStream& operator<<( const ArrayTerminator& rhs ); - -private: - - char *BeginElement( char *beginPtr ); - void EndElement( char *endPtr ); - - bool ElementSizeSlotRequired() const; - void CheckForAvailableBundleSpace(); - void CheckForAvailableMessageSpace( const char *addressPattern ); - void CheckForAvailableArgumentSpace( std::size_t argumentLength ); - - char *data_; - char *end_; - - char *typeTagsCurrent_; // stored in reverse order - char *messageCursor_; - char *argumentCurrent_; - - // elementSizePtr_ has two special values: 0 indicates that a bundle - // isn't open, and elementSizePtr_==data_ indicates that a bundle is - // open but that it doesn't have a size slot (ie the outermost bundle) - uint32 *elementSizePtr_; - - bool messageIsInProgress_; -}; - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_OSCOUTBOUNDPACKETSTREAM_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscPacketListener.h b/modules/touch/ext/libTUIO/oscpack/osc/OscPacketListener.h deleted file mode 100644 index 472cb1066f..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscPacketListener.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_OSCPACKETLISTENER_H -#define INCLUDED_OSCPACK_OSCPACKETLISTENER_H - -#include "OscReceivedElements.h" -#include "../ip/PacketListener.h" - - -namespace osc{ - -class OscPacketListener : public PacketListener{ -protected: - virtual void ProcessBundle( const osc::ReceivedBundle& b, - const IpEndpointName& remoteEndpoint ) - { - // ignore bundle time tag for now - - for( ReceivedBundle::const_iterator i = b.ElementsBegin(); - i != b.ElementsEnd(); ++i ){ - if( i->IsBundle() ) - ProcessBundle( ReceivedBundle(*i), remoteEndpoint ); - else - ProcessMessage( ReceivedMessage(*i), remoteEndpoint ); - } - } - - virtual void ProcessMessage( const osc::ReceivedMessage& m, - const IpEndpointName& remoteEndpoint ) = 0; - -public: - virtual void ProcessPacket( const char *data, int size, - const IpEndpointName& remoteEndpoint ) - { - osc::ReceivedPacket p( data, size ); - if( p.IsBundle() ) - ProcessBundle( ReceivedBundle(p), remoteEndpoint ); - else - ProcessMessage( ReceivedMessage(p), remoteEndpoint ); - } -}; - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_OSCPACKETLISTENER_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.cpp deleted file mode 100644 index bc1689bc1d..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "OscPrintReceivedElements.h" - -#include -#include -#include -#include - -#if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug -namespace std { -using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. -} -#endif - -namespace osc{ - - -std::ostream& operator<<( std::ostream & os, - const ReceivedMessageArgument& arg ) -{ - switch( arg.TypeTag() ){ - case TRUE_TYPE_TAG: - os << "bool:true"; - break; - - case FALSE_TYPE_TAG: - os << "bool:false"; - break; - - case NIL_TYPE_TAG: - os << "(Nil)"; - break; - - case INFINITUM_TYPE_TAG: - os << "(Infinitum)"; - break; - - case INT32_TYPE_TAG: - os << "int32:" << arg.AsInt32Unchecked(); - break; - - case FLOAT_TYPE_TAG: - os << "float32:" << arg.AsFloatUnchecked(); - break; - - case CHAR_TYPE_TAG: - { - char s[2] = {0}; - s[0] = arg.AsCharUnchecked(); - os << "char:'" << s << "'"; - } - break; - - case RGBA_COLOR_TYPE_TAG: - { - uint32 color = arg.AsRgbaColorUnchecked(); - - os << "RGBA:0x" - << std::hex << std::setfill('0') - << std::setw(2) << (int)((color>>24) & 0xFF) - << std::setw(2) << (int)((color>>16) & 0xFF) - << std::setw(2) << (int)((color>>8) & 0xFF) - << std::setw(2) << (int)(color & 0xFF) - << std::setfill(' '); - os.unsetf(std::ios::basefield); - } - break; - - case MIDI_MESSAGE_TYPE_TAG: - { - uint32 m = arg.AsMidiMessageUnchecked(); - os << "midi (port, status, data1, data2):<<" - << std::hex << std::setfill('0') - << "0x" << std::setw(2) << (int)((m>>24) & 0xFF) - << " 0x" << std::setw(2) << (int)((m>>16) & 0xFF) - << " 0x" << std::setw(2) << (int)((m>>8) & 0xFF) - << " 0x" << std::setw(2) << (int)(m & 0xFF) - << std::setfill(' ') << ">>"; - os.unsetf(std::ios::basefield); - } - break; - - case INT64_TYPE_TAG: - os << "int64:" << arg.AsInt64Unchecked(); - break; - - case TIME_TAG_TYPE_TAG: - { - os << "OSC-timetag:" << arg.AsTimeTagUnchecked() << " "; - - std::time_t t = - (unsigned long)( arg.AsTimeTagUnchecked() >> 32 ); - - const char *timeString = std::ctime( &t ); - size_t len = std::strlen( timeString ); - - // -1 to omit trailing newline from string returned by ctime() - if( len > 1 ) - os.write( timeString, len - 1 ); - } - break; - - case DOUBLE_TYPE_TAG: - os << "double:" << arg.AsDoubleUnchecked(); - break; - - case STRING_TYPE_TAG: - os << "OSC-string:`" << arg.AsStringUnchecked() << "'"; - break; - - case SYMBOL_TYPE_TAG: - os << "OSC-string (symbol):`" << arg.AsSymbolUnchecked() << "'"; - break; - - case BLOB_TYPE_TAG: - { - const void *data; - osc_bundle_element_size_t size; - arg.AsBlobUnchecked( data, size ); - os << "OSC-blob:<<" << std::hex << std::setfill('0'); - unsigned char *p = (unsigned char*)data; - for( osc_bundle_element_size_t i = 0; i < size; ++i ){ - os << "0x" << std::setw(2) << int(p[i]); - if( i != size-1 ) - os << ' '; - } - os.unsetf(std::ios::basefield); - os << ">>" << std::setfill(' '); - } - break; - - case ARRAY_BEGIN_TYPE_TAG: - os << "["; - break; - - case ARRAY_END_TYPE_TAG: - os << "]"; - break; - - default: - os << "unknown"; - } - - return os; -} - - -std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ) -{ - os << "["; - if( m.AddressPatternIsUInt32() ) - os << m.AddressPatternAsUInt32(); - else - os << m.AddressPattern(); - - bool first = true; - for( ReceivedMessage::const_iterator i = m.ArgumentsBegin(); - i != m.ArgumentsEnd(); ++i ){ - if( first ){ - os << " "; - first = false; - }else{ - os << ", "; - } - - os << *i; - } - - os << "]"; - - return os; -} - - -std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ) -{ - static int indent = 0; - - for( int j=0; j < indent; ++j ) - os << " "; - os << "{ ( "; - if( b.TimeTag() == 1 ) - os << "immediate"; - else - os << b.TimeTag(); - os << " )\n"; - - ++indent; - - for( ReceivedBundle::const_iterator i = b.ElementsBegin(); - i != b.ElementsEnd(); ++i ){ - if( i->IsBundle() ){ - ReceivedBundle b(*i); - os << b << "\n"; - }else{ - ReceivedMessage m(*i); - for( int j=0; j < indent; ++j ) - os << " "; - os << m << "\n"; - } - } - - --indent; - - for( int j=0; j < indent; ++j ) - os << " "; - os << "}"; - - return os; -} - - -std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ) -{ - if( p.IsBundle() ){ - ReceivedBundle b(p); - os << b << "\n"; - }else{ - ReceivedMessage m(p); - os << m << "\n"; - } - - return os; -} - -} // namespace osc diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.h b/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.h deleted file mode 100644 index 8d71391f0c..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscPrintReceivedElements.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H -#define INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H - -#include - -#include "OscReceivedElements.h" - - -namespace osc{ - -std::ostream& operator<<( std::ostream & os, const ReceivedPacket& p ); -std::ostream& operator<<( std::ostream & os, const ReceivedMessageArgument& arg ); -std::ostream& operator<<( std::ostream & os, const ReceivedMessage& m ); -std::ostream& operator<<( std::ostream & os, const ReceivedBundle& b ); - -} // namespace osc - -#endif /* INCLUDED_OSCPACK_OSCPRINTRECEIVEDELEMENTS_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.cpp deleted file mode 100644 index 14bbe39c19..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.cpp +++ /dev/null @@ -1,796 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "OscReceivedElements.h" - -#include "OscHostEndianness.h" - -#include // ptrdiff_t - -namespace osc{ - - -// return the first 4 byte boundary after the end of a str4 -// be careful about calling this version if you don't know whether -// the string is terminated correctly. -static inline const char* FindStr4End( const char *p ) -{ - if( p[0] == '\0' ) // special case for SuperCollider integer address pattern - return p + 4; - - p += 3; - - while( *p ) - p += 4; - - return p + 1; -} - - -// return the first 4 byte boundary after the end of a str4 -// returns 0 if p == end or if the string is unterminated -static inline const char* FindStr4End( const char *p, const char *end ) -{ - if( p >= end ) - return 0; - - if( p[0] == '\0' ) // special case for SuperCollider integer address pattern - return p + 4; - - p += 3; - end -= 1; - - while( p < end && *p ) - p += 4; - - if( *p ) - return 0; - else - return p + 1; -} - - -// round up to the next highest multiple of 4. unless x is already a multiple of 4 -static inline uint32 RoundUp4( uint32 x ) -{ - return (x + 3) & ~((uint32)0x03); -} - - -static inline int32 ToInt32( const char *p ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::int32 i; - char c[4]; - } u; - - u.c[0] = p[3]; - u.c[1] = p[2]; - u.c[2] = p[1]; - u.c[3] = p[0]; - - return u.i; -#else - return *(int32*)p; -#endif -} - - -static inline uint32 ToUInt32( const char *p ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::uint32 i; - char c[4]; - } u; - - u.c[0] = p[3]; - u.c[1] = p[2]; - u.c[2] = p[1]; - u.c[3] = p[0]; - - return u.i; -#else - return *(uint32*)p; -#endif -} - - -static inline int64 ToInt64( const char *p ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::int64 i; - char c[8]; - } u; - - u.c[0] = p[7]; - u.c[1] = p[6]; - u.c[2] = p[5]; - u.c[3] = p[4]; - u.c[4] = p[3]; - u.c[5] = p[2]; - u.c[6] = p[1]; - u.c[7] = p[0]; - - return u.i; -#else - return *(int64*)p; -#endif -} - - -static inline uint64 ToUInt64( const char *p ) -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::uint64 i; - char c[8]; - } u; - - u.c[0] = p[7]; - u.c[1] = p[6]; - u.c[2] = p[5]; - u.c[3] = p[4]; - u.c[4] = p[3]; - u.c[5] = p[2]; - u.c[6] = p[1]; - u.c[7] = p[0]; - - return u.i; -#else - return *(uint64*)p; -#endif -} - -//------------------------------------------------------------------------------ - -bool ReceivedPacket::IsBundle() const -{ - return (Size() > 0 && Contents()[0] == '#'); -} - -//------------------------------------------------------------------------------ - -bool ReceivedBundleElement::IsBundle() const -{ - return (Size() > 0 && Contents()[0] == '#'); -} - - -osc_bundle_element_size_t ReceivedBundleElement::Size() const -{ - return ToInt32( sizePtr_ ); -} - -//------------------------------------------------------------------------------ - -bool ReceivedMessageArgument::AsBool() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == TRUE_TYPE_TAG ) - return true; - else if( *typeTagPtr_ == FALSE_TYPE_TAG ) - return false; - else - throw WrongArgumentTypeException(); -} - - -bool ReceivedMessageArgument::AsBoolUnchecked() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == TRUE_TYPE_TAG ) - return true; - else - return false; -} - - -int32 ReceivedMessageArgument::AsInt32() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == INT32_TYPE_TAG ) - return AsInt32Unchecked(); - else - throw WrongArgumentTypeException(); -} - - -int32 ReceivedMessageArgument::AsInt32Unchecked() const -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - osc::int32 i; - char c[4]; - } u; - - u.c[0] = argumentPtr_[3]; - u.c[1] = argumentPtr_[2]; - u.c[2] = argumentPtr_[1]; - u.c[3] = argumentPtr_[0]; - - return u.i; -#else - return *(int32*)argumentPtr_; -#endif -} - - -float ReceivedMessageArgument::AsFloat() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == FLOAT_TYPE_TAG ) - return AsFloatUnchecked(); - else - throw WrongArgumentTypeException(); -} - - -float ReceivedMessageArgument::AsFloatUnchecked() const -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - float f; - char c[4]; - } u; - - u.c[0] = argumentPtr_[3]; - u.c[1] = argumentPtr_[2]; - u.c[2] = argumentPtr_[1]; - u.c[3] = argumentPtr_[0]; - - return u.f; -#else - return *(float*)argumentPtr_; -#endif -} - - -char ReceivedMessageArgument::AsChar() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == CHAR_TYPE_TAG ) - return AsCharUnchecked(); - else - throw WrongArgumentTypeException(); -} - - -char ReceivedMessageArgument::AsCharUnchecked() const -{ - return (char)ToInt32( argumentPtr_ ); -} - - -uint32 ReceivedMessageArgument::AsRgbaColor() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == RGBA_COLOR_TYPE_TAG ) - return AsRgbaColorUnchecked(); - else - throw WrongArgumentTypeException(); -} - - -uint32 ReceivedMessageArgument::AsRgbaColorUnchecked() const -{ - return ToUInt32( argumentPtr_ ); -} - - -uint32 ReceivedMessageArgument::AsMidiMessage() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG ) - return AsMidiMessageUnchecked(); - else - throw WrongArgumentTypeException(); -} - - -uint32 ReceivedMessageArgument::AsMidiMessageUnchecked() const -{ - return ToUInt32( argumentPtr_ ); -} - - -int64 ReceivedMessageArgument::AsInt64() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == INT64_TYPE_TAG ) - return AsInt64Unchecked(); - else - throw WrongArgumentTypeException(); -} - - -int64 ReceivedMessageArgument::AsInt64Unchecked() const -{ - return ToInt64( argumentPtr_ ); -} - - -uint64 ReceivedMessageArgument::AsTimeTag() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == TIME_TAG_TYPE_TAG ) - return AsTimeTagUnchecked(); - else - throw WrongArgumentTypeException(); -} - - -uint64 ReceivedMessageArgument::AsTimeTagUnchecked() const -{ - return ToUInt64( argumentPtr_ ); -} - - -double ReceivedMessageArgument::AsDouble() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == DOUBLE_TYPE_TAG ) - return AsDoubleUnchecked(); - else - throw WrongArgumentTypeException(); -} - - -double ReceivedMessageArgument::AsDoubleUnchecked() const -{ -#ifdef OSC_HOST_LITTLE_ENDIAN - union{ - double d; - char c[8]; - } u; - - u.c[0] = argumentPtr_[7]; - u.c[1] = argumentPtr_[6]; - u.c[2] = argumentPtr_[5]; - u.c[3] = argumentPtr_[4]; - u.c[4] = argumentPtr_[3]; - u.c[5] = argumentPtr_[2]; - u.c[6] = argumentPtr_[1]; - u.c[7] = argumentPtr_[0]; - - return u.d; -#else - return *(double*)argumentPtr_; -#endif -} - - -const char* ReceivedMessageArgument::AsString() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == STRING_TYPE_TAG ) - return argumentPtr_; - else - throw WrongArgumentTypeException(); -} - - -const char* ReceivedMessageArgument::AsSymbol() const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == SYMBOL_TYPE_TAG ) - return argumentPtr_; - else - throw WrongArgumentTypeException(); -} - - -void ReceivedMessageArgument::AsBlob( const void*& data, osc_bundle_element_size_t& size ) const -{ - if( !typeTagPtr_ ) - throw MissingArgumentException(); - else if( *typeTagPtr_ == BLOB_TYPE_TAG ) - AsBlobUnchecked( data, size ); - else - throw WrongArgumentTypeException(); -} - - -void ReceivedMessageArgument::AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const -{ - // read blob size as an unsigned int then validate - osc_bundle_element_size_t sizeResult = (osc_bundle_element_size_t)ToUInt32( argumentPtr_ ); - if( !IsValidElementSizeValue(sizeResult) ) - throw MalformedMessageException("invalid blob size"); - - size = sizeResult; - data = (void*)(argumentPtr_+ osc::OSC_SIZEOF_INT32); -} - -std::size_t ReceivedMessageArgument::ComputeArrayItemCount() const -{ - // it is only valid to call ComputeArrayItemCount when the argument is the array start marker - if( !IsArrayBegin() ) - throw WrongArgumentTypeException(); - - std::size_t result = 0; - unsigned int level = 0; - const char *typeTag = typeTagPtr_ + 1; - - // iterate through all type tags. note that ReceivedMessage::Init - // has already checked that the message is well formed. - while( *typeTag ) { - switch( *typeTag++ ) { - case ARRAY_BEGIN_TYPE_TAG: - level += 1; - break; - - case ARRAY_END_TYPE_TAG: - if(level == 0) - return result; - level -= 1; - break; - - default: - if( level == 0 ) // only count items at level 0 - ++result; - } - } - - return result; -} - -//------------------------------------------------------------------------------ - -void ReceivedMessageArgumentIterator::Advance() -{ - if( !value_.typeTagPtr_ ) - return; - - switch( *value_.typeTagPtr_++ ){ - case '\0': - // don't advance past end - --value_.typeTagPtr_; - break; - - case TRUE_TYPE_TAG: - case FALSE_TYPE_TAG: - case NIL_TYPE_TAG: - case INFINITUM_TYPE_TAG: - - // zero length - break; - - case INT32_TYPE_TAG: - case FLOAT_TYPE_TAG: - case CHAR_TYPE_TAG: - case RGBA_COLOR_TYPE_TAG: - case MIDI_MESSAGE_TYPE_TAG: - - value_.argumentPtr_ += 4; - break; - - case INT64_TYPE_TAG: - case TIME_TAG_TYPE_TAG: - case DOUBLE_TYPE_TAG: - - value_.argumentPtr_ += 8; - break; - - case STRING_TYPE_TAG: - case SYMBOL_TYPE_TAG: - - // we use the unsafe function FindStr4End(char*) here because all of - // the arguments have already been validated in - // ReceivedMessage::Init() below. - - value_.argumentPtr_ = FindStr4End( value_.argumentPtr_ ); - break; - - case BLOB_TYPE_TAG: - { - // treat blob size as an unsigned int for the purposes of this calculation - uint32 blobSize = ToUInt32( value_.argumentPtr_ ); - value_.argumentPtr_ = value_.argumentPtr_ + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize ); - } - break; - - case ARRAY_BEGIN_TYPE_TAG: - case ARRAY_END_TYPE_TAG: - - // [ Indicates the beginning of an array. The tags following are for - // data in the Array until a close brace tag is reached. - // ] Indicates the end of an array. - - // zero length, don't advance argument ptr - break; - - default: // unknown type tag - // don't advance - --value_.typeTagPtr_; - break; - } -} - -//------------------------------------------------------------------------------ - -ReceivedMessage::ReceivedMessage( const ReceivedPacket& packet ) - : addressPattern_( packet.Contents() ) -{ - Init( packet.Contents(), packet.Size() ); -} - - -ReceivedMessage::ReceivedMessage( const ReceivedBundleElement& bundleElement ) - : addressPattern_( bundleElement.Contents() ) -{ - Init( bundleElement.Contents(), bundleElement.Size() ); -} - - -bool ReceivedMessage::AddressPatternIsUInt32() const -{ - return (addressPattern_[0] == '\0'); -} - - -uint32 ReceivedMessage::AddressPatternAsUInt32() const -{ - return ToUInt32( addressPattern_ ); -} - - -void ReceivedMessage::Init( const char *message, osc_bundle_element_size_t size ) -{ - if( !IsValidElementSizeValue(size) ) - throw MalformedMessageException( "invalid message size" ); - - if( size == 0 ) - throw MalformedMessageException( "zero length messages not permitted" ); - - if( !IsMultipleOf4(size) ) - throw MalformedMessageException( "message size must be multiple of four" ); - - const char *end = message + size; - - typeTagsBegin_ = FindStr4End( addressPattern_, end ); - if( typeTagsBegin_ == 0 ){ - // address pattern was not terminated before end - throw MalformedMessageException( "unterminated address pattern" ); - } - - if( typeTagsBegin_ == end ){ - // message consists of only the address pattern - no arguments or type tags. - typeTagsBegin_ = 0; - typeTagsEnd_ = 0; - arguments_ = 0; - - }else{ - if( *typeTagsBegin_ != ',' ) - throw MalformedMessageException( "type tags not present" ); - - if( *(typeTagsBegin_ + 1) == '\0' ){ - // zero length type tags - typeTagsBegin_ = 0; - typeTagsEnd_ = 0; - arguments_ = 0; - - }else{ - // check that all arguments are present and well formed - - arguments_ = FindStr4End( typeTagsBegin_, end ); - if( arguments_ == 0 ){ - throw MalformedMessageException( "type tags were not terminated before end of message" ); - } - - ++typeTagsBegin_; // advance past initial ',' - - const char *typeTag = typeTagsBegin_; - const char *argument = arguments_; - unsigned int arrayLevel = 0; - - do{ - switch( *typeTag ){ - case TRUE_TYPE_TAG: - case FALSE_TYPE_TAG: - case NIL_TYPE_TAG: - case INFINITUM_TYPE_TAG: - // zero length - break; - - // [ Indicates the beginning of an array. The tags following are for - // data in the Array until a close brace tag is reached. - // ] Indicates the end of an array. - case ARRAY_BEGIN_TYPE_TAG: - ++arrayLevel; - // (zero length argument data) - break; - - case ARRAY_END_TYPE_TAG: - --arrayLevel; - // (zero length argument data) - break; - - case INT32_TYPE_TAG: - case FLOAT_TYPE_TAG: - case CHAR_TYPE_TAG: - case RGBA_COLOR_TYPE_TAG: - case MIDI_MESSAGE_TYPE_TAG: - - if( argument == end ) - throw MalformedMessageException( "arguments exceed message size" ); - argument += 4; - if( argument > end ) - throw MalformedMessageException( "arguments exceed message size" ); - break; - - case INT64_TYPE_TAG: - case TIME_TAG_TYPE_TAG: - case DOUBLE_TYPE_TAG: - - if( argument == end ) - throw MalformedMessageException( "arguments exceed message size" ); - argument += 8; - if( argument > end ) - throw MalformedMessageException( "arguments exceed message size" ); - break; - - case STRING_TYPE_TAG: - case SYMBOL_TYPE_TAG: - - if( argument == end ) - throw MalformedMessageException( "arguments exceed message size" ); - argument = FindStr4End( argument, end ); - if( argument == 0 ) - throw MalformedMessageException( "unterminated string argument" ); - break; - - case BLOB_TYPE_TAG: - { - if( argument + osc::OSC_SIZEOF_INT32 > end ) - MalformedMessageException( "arguments exceed message size" ); - - // treat blob size as an unsigned int for the purposes of this calculation - uint32 blobSize = ToUInt32( argument ); - argument = argument + osc::OSC_SIZEOF_INT32 + RoundUp4( blobSize ); - if( argument > end ) - MalformedMessageException( "arguments exceed message size" ); - } - break; - - default: - throw MalformedMessageException( "unknown type tag" ); - } - - }while( *++typeTag != '\0' ); - typeTagsEnd_ = typeTag; - - if( arrayLevel != 0 ) - throw MalformedMessageException( "array was not terminated before end of message (expected ']' end of array tag)" ); - } - - // These invariants should be guaranteed by the above code. - // we depend on them in the implementation of ArgumentCount() -#ifndef NDEBUG - std::ptrdiff_t argumentCount = typeTagsEnd_ - typeTagsBegin_; - assert( argumentCount >= 0 ); - assert( argumentCount <= OSC_INT32_MAX ); -#endif - } -} - -//------------------------------------------------------------------------------ - -ReceivedBundle::ReceivedBundle( const ReceivedPacket& packet ) - : elementCount_( 0 ) -{ - Init( packet.Contents(), packet.Size() ); -} - - -ReceivedBundle::ReceivedBundle( const ReceivedBundleElement& bundleElement ) - : elementCount_( 0 ) -{ - Init( bundleElement.Contents(), bundleElement.Size() ); -} - - -void ReceivedBundle::Init( const char *bundle, osc_bundle_element_size_t size ) -{ - - if( !IsValidElementSizeValue(size) ) - throw MalformedBundleException( "invalid bundle size" ); - - if( size < 16 ) - throw MalformedBundleException( "packet too short for bundle" ); - - if( !IsMultipleOf4(size) ) - throw MalformedBundleException( "bundle size must be multiple of four" ); - - if( bundle[0] != '#' - || bundle[1] != 'b' - || bundle[2] != 'u' - || bundle[3] != 'n' - || bundle[4] != 'd' - || bundle[5] != 'l' - || bundle[6] != 'e' - || bundle[7] != '\0' ) - throw MalformedBundleException( "bad bundle address pattern" ); - - end_ = bundle + size; - - timeTag_ = bundle + 8; - - const char *p = timeTag_ + 8; - - while( p < end_ ){ - if( p + osc::OSC_SIZEOF_INT32 > end_ ) - throw MalformedBundleException( "packet too short for elementSize" ); - - // treat element size as an unsigned int for the purposes of this calculation - uint32 elementSize = ToUInt32( p ); - if( (elementSize & ((uint32)0x03)) != 0 ) - throw MalformedBundleException( "bundle element size must be multiple of four" ); - - p += osc::OSC_SIZEOF_INT32 + elementSize; - if( p > end_ ) - throw MalformedBundleException( "packet too short for bundle element" ); - - ++elementCount_; - } - - if( p != end_ ) - throw MalformedBundleException( "bundle contents " ); -} - - -uint64 ReceivedBundle::TimeTag() const -{ - return ToUInt64( timeTag_ ); -} - - -} // namespace osc - diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.h b/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.h deleted file mode 100644 index 69d0e6c545..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscReceivedElements.h +++ /dev/null @@ -1,548 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H -#define INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H - -#include -#include -#include // size_t - -#include "OscTypes.h" -#include "OscException.h" - - -namespace osc{ - - -class MalformedPacketException : public Exception{ -public: - MalformedPacketException( const char *w="malformed packet" ) - : Exception( w ) {} -}; - -class MalformedMessageException : public Exception{ -public: - MalformedMessageException( const char *w="malformed message" ) - : Exception( w ) {} -}; - -class MalformedBundleException : public Exception{ -public: - MalformedBundleException( const char *w="malformed bundle" ) - : Exception( w ) {} -}; - -class WrongArgumentTypeException : public Exception{ -public: - WrongArgumentTypeException( const char *w="wrong argument type" ) - : Exception( w ) {} -}; - -class MissingArgumentException : public Exception{ -public: - MissingArgumentException( const char *w="missing argument" ) - : Exception( w ) {} -}; - -class ExcessArgumentException : public Exception{ -public: - ExcessArgumentException( const char *w="too many arguments" ) - : Exception( w ) {} -}; - - -class ReceivedPacket{ -public: - // Although the OSC spec is not entirely clear on this, we only support - // packets up to 0x7FFFFFFC bytes long (the maximum 4-byte aligned value - // representable by an int32). An exception will be raised if you pass a - // larger value to the ReceivedPacket() constructor. - - ReceivedPacket( const char *contents, osc_bundle_element_size_t size ) - : contents_( contents ) - , size_( ValidateSize(size) ) {} - - ReceivedPacket( const char *contents, std::size_t size ) - : contents_( contents ) - , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} - -#if !(defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)) - ReceivedPacket( const char *contents, int size ) - : contents_( contents ) - , size_( ValidateSize( (osc_bundle_element_size_t)size ) ) {} -#endif - - bool IsMessage() const { return !IsBundle(); } - bool IsBundle() const; - - osc_bundle_element_size_t Size() const { return size_; } - const char *Contents() const { return contents_; } - -private: - const char *contents_; - osc_bundle_element_size_t size_; - - static osc_bundle_element_size_t ValidateSize( osc_bundle_element_size_t size ) - { - // sanity check integer types declared in OscTypes.h - // you'll need to fix OscTypes.h if any of these asserts fail - assert( sizeof(osc::int32) == 4 ); - assert( sizeof(osc::uint32) == 4 ); - assert( sizeof(osc::int64) == 8 ); - assert( sizeof(osc::uint64) == 8 ); - - if( !IsValidElementSizeValue(size) ) - throw MalformedPacketException( "invalid packet size" ); - - if( size == 0 ) - throw MalformedPacketException( "zero length elements not permitted" ); - - if( !IsMultipleOf4(size) ) - throw MalformedPacketException( "element size must be multiple of four" ); - - return size; - } -}; - - -class ReceivedBundleElement{ -public: - ReceivedBundleElement( const char *sizePtr ) - : sizePtr_( sizePtr ) {} - - friend class ReceivedBundleElementIterator; - - bool IsMessage() const { return !IsBundle(); } - bool IsBundle() const; - - osc_bundle_element_size_t Size() const; - const char *Contents() const { return sizePtr_ + osc::OSC_SIZEOF_INT32; } - -private: - const char *sizePtr_; -}; - - -class ReceivedBundleElementIterator{ -public: - ReceivedBundleElementIterator( const char *sizePtr ) - : value_( sizePtr ) {} - - ReceivedBundleElementIterator operator++() - { - Advance(); - return *this; - } - - ReceivedBundleElementIterator operator++(int) - { - ReceivedBundleElementIterator old( *this ); - Advance(); - return old; - } - - const ReceivedBundleElement& operator*() const { return value_; } - - const ReceivedBundleElement* operator->() const { return &value_; } - - friend bool operator==(const ReceivedBundleElementIterator& lhs, - const ReceivedBundleElementIterator& rhs ); - -private: - ReceivedBundleElement value_; - - void Advance() { value_.sizePtr_ = value_.Contents() + value_.Size(); } - - bool IsEqualTo( const ReceivedBundleElementIterator& rhs ) const - { - return value_.sizePtr_ == rhs.value_.sizePtr_; - } -}; - -inline bool operator==(const ReceivedBundleElementIterator& lhs, - const ReceivedBundleElementIterator& rhs ) -{ - return lhs.IsEqualTo( rhs ); -} - -inline bool operator!=(const ReceivedBundleElementIterator& lhs, - const ReceivedBundleElementIterator& rhs ) -{ - return !( lhs == rhs ); -} - - -class ReceivedMessageArgument{ -public: - ReceivedMessageArgument( const char *typeTagPtr, const char *argumentPtr ) - : typeTagPtr_( typeTagPtr ) - , argumentPtr_( argumentPtr ) {} - - friend class ReceivedMessageArgumentIterator; - - char TypeTag() const { return *typeTagPtr_; } - - // the unchecked methods below don't check whether the argument actually - // is of the specified type. they should only be used if you've already - // checked the type tag or the associated IsType() method. - - bool IsBool() const - { return *typeTagPtr_ == TRUE_TYPE_TAG || *typeTagPtr_ == FALSE_TYPE_TAG; } - bool AsBool() const; - bool AsBoolUnchecked() const; - - bool IsNil() const { return *typeTagPtr_ == NIL_TYPE_TAG; } - bool IsInfinitum() const { return *typeTagPtr_ == INFINITUM_TYPE_TAG; } - - bool IsInt32() const { return *typeTagPtr_ == INT32_TYPE_TAG; } - int32 AsInt32() const; - int32 AsInt32Unchecked() const; - - bool IsFloat() const { return *typeTagPtr_ == FLOAT_TYPE_TAG; } - float AsFloat() const; - float AsFloatUnchecked() const; - - bool IsChar() const { return *typeTagPtr_ == CHAR_TYPE_TAG; } - char AsChar() const; - char AsCharUnchecked() const; - - bool IsRgbaColor() const { return *typeTagPtr_ == RGBA_COLOR_TYPE_TAG; } - uint32 AsRgbaColor() const; - uint32 AsRgbaColorUnchecked() const; - - bool IsMidiMessage() const { return *typeTagPtr_ == MIDI_MESSAGE_TYPE_TAG; } - uint32 AsMidiMessage() const; - uint32 AsMidiMessageUnchecked() const; - - bool IsInt64() const { return *typeTagPtr_ == INT64_TYPE_TAG; } - int64 AsInt64() const; - int64 AsInt64Unchecked() const; - - bool IsTimeTag() const { return *typeTagPtr_ == TIME_TAG_TYPE_TAG; } - uint64 AsTimeTag() const; - uint64 AsTimeTagUnchecked() const; - - bool IsDouble() const { return *typeTagPtr_ == DOUBLE_TYPE_TAG; } - double AsDouble() const; - double AsDoubleUnchecked() const; - - bool IsString() const { return *typeTagPtr_ == STRING_TYPE_TAG; } - const char* AsString() const; - const char* AsStringUnchecked() const { return argumentPtr_; } - - bool IsSymbol() const { return *typeTagPtr_ == SYMBOL_TYPE_TAG; } - const char* AsSymbol() const; - const char* AsSymbolUnchecked() const { return argumentPtr_; } - - bool IsBlob() const { return *typeTagPtr_ == BLOB_TYPE_TAG; } - void AsBlob( const void*& data, osc_bundle_element_size_t& size ) const; - void AsBlobUnchecked( const void*& data, osc_bundle_element_size_t& size ) const; - - bool IsArrayBegin() const { return *typeTagPtr_ == ARRAY_BEGIN_TYPE_TAG; } - bool IsArrayEnd() const { return *typeTagPtr_ == ARRAY_END_TYPE_TAG; } - // Calculate the number of top-level items in the array. Nested arrays count as one item. - // Only valid at array start. Will throw an exception if IsArrayStart() == false. - std::size_t ComputeArrayItemCount() const; - -private: - const char *typeTagPtr_; - const char *argumentPtr_; -}; - - -class ReceivedMessageArgumentIterator{ -public: - ReceivedMessageArgumentIterator( const char *typeTags, const char *arguments ) - : value_( typeTags, arguments ) {} - - ReceivedMessageArgumentIterator operator++() - { - Advance(); - return *this; - } - - ReceivedMessageArgumentIterator operator++(int) - { - ReceivedMessageArgumentIterator old( *this ); - Advance(); - return old; - } - - const ReceivedMessageArgument& operator*() const { return value_; } - - const ReceivedMessageArgument* operator->() const { return &value_; } - - friend bool operator==(const ReceivedMessageArgumentIterator& lhs, - const ReceivedMessageArgumentIterator& rhs ); - -private: - ReceivedMessageArgument value_; - - void Advance(); - - bool IsEqualTo( const ReceivedMessageArgumentIterator& rhs ) const - { - return value_.typeTagPtr_ == rhs.value_.typeTagPtr_; - } -}; - -inline bool operator==(const ReceivedMessageArgumentIterator& lhs, - const ReceivedMessageArgumentIterator& rhs ) -{ - return lhs.IsEqualTo( rhs ); -} - -inline bool operator!=(const ReceivedMessageArgumentIterator& lhs, - const ReceivedMessageArgumentIterator& rhs ) -{ - return !( lhs == rhs ); -} - - -class ReceivedMessageArgumentStream{ - friend class ReceivedMessage; - ReceivedMessageArgumentStream( const ReceivedMessageArgumentIterator& begin, - const ReceivedMessageArgumentIterator& end ) - : p_( begin ) - , end_( end ) {} - - ReceivedMessageArgumentIterator p_, end_; - -public: - - // end of stream - bool Eos() const { return p_ == end_; } - - ReceivedMessageArgumentStream& operator>>( bool& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsBool(); - return *this; - } - - // not sure if it would be useful to stream Nil and Infinitum - // for now it's not possible - // same goes for array boundaries - - ReceivedMessageArgumentStream& operator>>( int32& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsInt32(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( float& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsFloat(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( char& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsChar(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( RgbaColor& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsRgbaColor(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( MidiMessage& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsMidiMessage(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( int64& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsInt64(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( TimeTag& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsTimeTag(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( double& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsDouble(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( Blob& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - (*p_++).AsBlob( rhs.data, rhs.size ); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( const char*& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs = (*p_++).AsString(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( Symbol& rhs ) - { - if( Eos() ) - throw MissingArgumentException(); - - rhs.value = (*p_++).AsSymbol(); - return *this; - } - - ReceivedMessageArgumentStream& operator>>( MessageTerminator& rhs ) - { - (void) rhs; // suppress unused parameter warning - - if( !Eos() ) - throw ExcessArgumentException(); - - return *this; - } -}; - - -class ReceivedMessage{ - void Init( const char *bundle, osc_bundle_element_size_t size ); -public: - explicit ReceivedMessage( const ReceivedPacket& packet ); - explicit ReceivedMessage( const ReceivedBundleElement& bundleElement ); - - const char *AddressPattern() const { return addressPattern_; } - - // Support for non-standard SuperCollider integer address patterns: - bool AddressPatternIsUInt32() const; - uint32 AddressPatternAsUInt32() const; - - uint32 ArgumentCount() const { return static_cast(typeTagsEnd_ - typeTagsBegin_); } - - const char *TypeTags() const { return typeTagsBegin_; } - - - typedef ReceivedMessageArgumentIterator const_iterator; - - ReceivedMessageArgumentIterator ArgumentsBegin() const - { - return ReceivedMessageArgumentIterator( typeTagsBegin_, arguments_ ); - } - - ReceivedMessageArgumentIterator ArgumentsEnd() const - { - return ReceivedMessageArgumentIterator( typeTagsEnd_, 0 ); - } - - ReceivedMessageArgumentStream ArgumentStream() const - { - return ReceivedMessageArgumentStream( ArgumentsBegin(), ArgumentsEnd() ); - } - -private: - const char *addressPattern_; - const char *typeTagsBegin_; - const char *typeTagsEnd_; - const char *arguments_; -}; - - -class ReceivedBundle{ - void Init( const char *message, osc_bundle_element_size_t size ); -public: - explicit ReceivedBundle( const ReceivedPacket& packet ); - explicit ReceivedBundle( const ReceivedBundleElement& bundleElement ); - - uint64 TimeTag() const; - - uint32 ElementCount() const { return elementCount_; } - - typedef ReceivedBundleElementIterator const_iterator; - - ReceivedBundleElementIterator ElementsBegin() const - { - return ReceivedBundleElementIterator( timeTag_ + 8 ); - } - - ReceivedBundleElementIterator ElementsEnd() const - { - return ReceivedBundleElementIterator( end_ ); - } - -private: - const char *timeTag_; - const char *end_; - uint32 elementCount_; -}; - - -} // namespace osc - - -#endif /* INCLUDED_OSCPACK_OSCRECEIVEDELEMENTS_H */ diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.cpp b/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.cpp deleted file mode 100644 index 444a9fed48..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#include "OscTypes.h" - -namespace osc{ - -BundleInitiator BeginBundleImmediate(1); -BundleTerminator EndBundle; -MessageTerminator EndMessage; -NilType OscNil; -#ifndef _OBJC_OBJC_H_ -NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead -#endif -InfinitumType Infinitum; -ArrayInitiator BeginArray; -ArrayTerminator EndArray; - -} // namespace osc diff --git a/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.h b/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.h deleted file mode 100644 index 53db577ea9..0000000000 --- a/modules/touch/ext/libTUIO/oscpack/osc/OscTypes.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - oscpack -- Open Sound Control (OSC) packet manipulation library - http://www.rossbencina.com/code/oscpack - - Copyright (c) 2004-2013 Ross Bencina - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files - (the "Software"), to deal in the Software without restriction, - including without limitation the rights to use, copy, modify, merge, - publish, distribute, sublicense, and/or sell copies of the Software, - and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - The text above constitutes the entire oscpack license; however, - the oscpack developer(s) also make the following non-binding requests: - - Any person wishing to distribute modifications to the Software is - requested to send the modifications to the original developer so that - they can be incorporated into the canonical version. It is also - requested that these non-binding requests be included whenever the - above license is reproduced. -*/ -#ifndef INCLUDED_OSCPACK_OSCTYPES_H -#define INCLUDED_OSCPACK_OSCTYPES_H - - -namespace osc{ - -// basic types - -#if defined(__BORLANDC__) || defined(_MSC_VER) - -typedef __int64 int64; -typedef unsigned __int64 uint64; - -#elif defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) - -typedef long int64; -typedef unsigned long uint64; - -#else - -typedef long long int64; -typedef unsigned long long uint64; - -#endif - - - -#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) - -typedef signed int int32; -typedef unsigned int uint32; - -#else - -typedef signed long int32; -typedef unsigned long uint32; - -#endif - - -enum ValueTypeSizes{ - OSC_SIZEOF_INT32 = 4, - OSC_SIZEOF_UINT32 = 4, - OSC_SIZEOF_INT64 = 8, - OSC_SIZEOF_UINT64 = 8, -}; - - -// osc_bundle_element_size_t is used for the size of bundle elements and blobs -// the OSC spec specifies these as int32 (signed) but we ensure that they -// are always positive since negative field sizes make no sense. - -typedef int32 osc_bundle_element_size_t; - -enum { - OSC_INT32_MAX = 0x7FFFFFFF, - - // Element sizes are specified to be int32, and are always rounded up to nearest - // multiple of 4. Therefore their values can't be greater than 0x7FFFFFFC. - OSC_BUNDLE_ELEMENT_SIZE_MAX = 0x7FFFFFFC -}; - - -inline bool IsValidElementSizeValue( osc_bundle_element_size_t x ) -{ - // sizes may not be negative or exceed OSC_BUNDLE_ELEMENT_SIZE_MAX - return x >= 0 && x <= OSC_BUNDLE_ELEMENT_SIZE_MAX; -} - - -inline bool IsMultipleOf4( osc_bundle_element_size_t x ) -{ - return (x & ((osc_bundle_element_size_t)0x03)) == 0; -} - - -enum TypeTagValues { - TRUE_TYPE_TAG = 'T', - FALSE_TYPE_TAG = 'F', - NIL_TYPE_TAG = 'N', - INFINITUM_TYPE_TAG = 'I', - INT32_TYPE_TAG = 'i', - FLOAT_TYPE_TAG = 'f', - CHAR_TYPE_TAG = 'c', - RGBA_COLOR_TYPE_TAG = 'r', - MIDI_MESSAGE_TYPE_TAG = 'm', - INT64_TYPE_TAG = 'h', - TIME_TAG_TYPE_TAG = 't', - DOUBLE_TYPE_TAG = 'd', - STRING_TYPE_TAG = 's', - SYMBOL_TYPE_TAG = 'S', - BLOB_TYPE_TAG = 'b', - ARRAY_BEGIN_TYPE_TAG = '[', - ARRAY_END_TYPE_TAG = ']' -}; - - - -// i/o manipulators used for streaming interfaces - -struct BundleInitiator{ - explicit BundleInitiator( uint64 timeTag_ ) : timeTag( timeTag_ ) {} - uint64 timeTag; -}; - -extern BundleInitiator BeginBundleImmediate; - -inline BundleInitiator BeginBundle( uint64 timeTag=1 ) -{ - return BundleInitiator(timeTag); -} - - -struct BundleTerminator{ -}; - -extern BundleTerminator EndBundle; - -struct BeginMessage{ - explicit BeginMessage( const char *addressPattern_ ) : addressPattern( addressPattern_ ) {} - const char *addressPattern; -}; - -struct MessageTerminator{ -}; - -extern MessageTerminator EndMessage; - - -// osc specific types. they are defined as structs so they can be used -// as separately identifiable types with the streaming operators. - -struct NilType{ -}; - -extern NilType OscNil; - -#ifndef _OBJC_OBJC_H_ -extern NilType Nil; // Objective-C defines Nil. so our Nil is deprecated. use OscNil instead -#endif - -struct InfinitumType{ -}; - -extern InfinitumType Infinitum; - -struct RgbaColor{ - RgbaColor() {} - explicit RgbaColor( uint32 value_ ) : value( value_ ) {} - uint32 value; - - operator uint32() const { return value; } -}; - - -struct MidiMessage{ - MidiMessage() {} - explicit MidiMessage( uint32 value_ ) : value( value_ ) {} - uint32 value; - - operator uint32() const { return value; } -}; - - -struct TimeTag{ - TimeTag() {} - explicit TimeTag( uint64 value_ ) : value( value_ ) {} - uint64 value; - - operator uint64() const { return value; } -}; - - -struct Symbol{ - Symbol() {} - explicit Symbol( const char* value_ ) : value( value_ ) {} - const char* value; - - operator const char *() const { return value; } -}; - - -struct Blob{ - Blob() {} - explicit Blob( const void* data_, osc_bundle_element_size_t size_ ) - : data( data_ ), size( size_ ) {} - const void* data; - osc_bundle_element_size_t size; -}; - -struct ArrayInitiator{ -}; - -extern ArrayInitiator BeginArray; - -struct ArrayTerminator{ -}; - -extern ArrayTerminator EndArray; - -} // namespace osc - - -#endif /* INCLUDED_OSCPACK_OSCTYPES_H */ From 53f6f92de04b0821c3b32ca04d7948236503b631 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Jul 2017 15:52:02 -0600 Subject: [PATCH 180/192] libTUIO11 as submodule --- .gitmodules | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitmodules b/.gitmodules index 207b84ddb5..4398b3eab5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,4 +12,5 @@ url = https://github.com/opensgct/sgct.git [submodule "modules/touch/ext/libTUIO11"] path = modules/touch/ext/libTUIO11 + url = https://github.com/mkalten/TUIO11_CPP From ed15412bcec896440393b5b6064fd5943cb70917 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Jul 2017 15:53:35 -0600 Subject: [PATCH 181/192] update libTUIO11 submodule --- modules/touch/ext/libTUIO11 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/touch/ext/libTUIO11 b/modules/touch/ext/libTUIO11 index 2e0d676754..a164db7a95 160000 --- a/modules/touch/ext/libTUIO11 +++ b/modules/touch/ext/libTUIO11 @@ -1 +1 @@ -Subproject commit 2e0d6767549122565d52067dae5f3f21af209e48 +Subproject commit a164db7a95420aa1cdcb7aec1b2cdf64827ebc57 From 3d5a0df33207cff3f813d1f2c8512dae177e0bd4 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Jul 2017 16:00:53 -0600 Subject: [PATCH 182/192] nitpicky no new line in for url --- .gitmodules | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 4398b3eab5..207b84ddb5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,5 +12,4 @@ url = https://github.com/opensgct/sgct.git [submodule "modules/touch/ext/libTUIO11"] path = modules/touch/ext/libTUIO11 - url = https://github.com/mkalten/TUIO11_CPP From 784343a7312bad900efb07690c02a5859bfb2d53 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Jul 2017 16:04:37 -0600 Subject: [PATCH 183/192] link to right directory for ext lib CMakeLists --- modules/touch/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/touch/CMakeLists.txt b/modules/touch/CMakeLists.txt index bceb2918a8..d8119f2d36 100644 --- a/modules/touch/CMakeLists.txt +++ b/modules/touch/CMakeLists.txt @@ -52,4 +52,4 @@ create_new_module( ${HEADER_FILES} ${SOURCE_FILES} ${SHADER_FILES} ) -include_external_library(${touch_module} libTUIO ${CMAKE_CURRENT_SOURCE_DIR}/ext/libTUIO) \ No newline at end of file +include_external_library(${touch_module} libTUIO11 ${CMAKE_CURRENT_SOURCE_DIR}/ext) \ No newline at end of file From 8b46b2a63ab3287169438f75213a591b6d28f49b Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Jul 2017 16:50:43 -0600 Subject: [PATCH 184/192] build fix by using new path to lib and adding CMake include paths --- modules/touch/ext/CMakeLists.txt | 66 ++++++++++++++++---------------- modules/touch/include/TuioEar.h | 8 ++-- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/modules/touch/ext/CMakeLists.txt b/modules/touch/ext/CMakeLists.txt index 93fbc534fe..0a8b432962 100644 --- a/modules/touch/ext/CMakeLists.txt +++ b/modules/touch/ext/CMakeLists.txt @@ -25,54 +25,54 @@ project(libTUIO11) message(STATUS "Generating libTUIO11 project") -include_directories(${PROJECT_SOURCE_DIR}/libTUIO11/TUIO) -include_directories(${PROJECT_SOURCE_DIR}/libTUIO11/oscpack) - set(TUIO_SOURCE ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/WebSockSender.cpp ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/UdpSender.cpp ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/UdpReceiver.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioTime.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioServer.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioPoint.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioObject.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioManager.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioDispatcher.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioCursor.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioContainer.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioClient.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioBlob.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TcpSender.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TcpReceiver.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/OscReceiver.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/OneEuroFilter.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/FlashSender.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioTime.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioServer.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioPoint.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioObject.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioManager.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioDispatcher.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioCursor.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioContainer.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioClient.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TuioBlob.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TcpSender.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/TcpReceiver.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/OscReceiver.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/OneEuroFilter.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO/FlashSender.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/IpEndpointName.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/IpEndpointName.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscTypes.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscReceivedElements.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscPrintReceivedElements.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscOutboundPacketStream.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscTypes.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscReceivedElements.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscPrintReceivedElements.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/osc/OscOutboundPacketStream.cpp ) if (WIN32) - set(TUIO_SOURCE - ${TUIO_SOURCE} - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/win32/NetworkingUtils.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/win32/UdpSocket.cpp + set(TUIO_SOURCE + ${TUIO_SOURCE} + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/win32/NetworkingUtils.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/win32/UdpSocket.cpp ) endif () if (UNIX) - set(TUIO_SOURCE - ${TUIO_SOURCE} - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/posix/NetworkingUtils.cpp - ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/posix/UdpSocket.cpp - ) + set(TUIO_SOURCE + ${TUIO_SOURCE} + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/posix/NetworkingUtils.cpp + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack/ip/posix/UdpSocket.cpp + ) endif () add_library(libTUIO11 ${TUIO_SOURCE} ) -target_include_directories(libTUIO11 PUBLIC ${PROJECT_SOURCE_DIR}libTUIO11/) \ No newline at end of file +target_include_directories(libTUIO11 PUBLIC + ${PROJECT_SOURCE_DIR}/libTUIO11/ + ${PROJECT_SOURCE_DIR}/libTUIO11/oscpack + ${PROJECT_SOURCE_DIR}/libTUIO11/TUIO) \ No newline at end of file diff --git a/modules/touch/include/TuioEar.h b/modules/touch/include/TuioEar.h index e61e655047..2029640a54 100644 --- a/modules/touch/include/TuioEar.h +++ b/modules/touch/include/TuioEar.h @@ -25,10 +25,10 @@ #ifndef __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__ #define __OPENSPACE_MODULE_TOUCH___TOUCHEAR___H__ -#include -#include -#include -#include +#include +#include +#include +#include #include From 135b1af324de5a918887ff8e4730b21ae6a7b1f7 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Thu, 13 Jul 2017 18:24:49 -0600 Subject: [PATCH 185/192] Fix config file. Merge. --- openspace.cfg | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openspace.cfg b/openspace.cfg index badbe6906e..85a125ca9e 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -48,7 +48,7 @@ return { CONFIG = "${BASE_PATH}/config", CACHE = "${BASE_PATH}/cache", FONTS = "${OPENSPACE_DATA}/fonts", - DOCUMENTATION = "${BASE_PATH}/documentation, + DOCUMENTATION = "${BASE_PATH}/documentation", LOGS = "${BASE_PATH}/logs" }, Fonts = { @@ -66,9 +66,11 @@ return { }, CapabilitiesVerbosity = "Full" }, + Launcher = { LogLevel = "None" }, + LuaDocumentation = "${DOCUMENTATION}/LuaScripting.html", PropertyDocumentation = "${DOCUMENTATION}/Properties.html", ScriptLog = "${LOGS}/ScriptLog.txt", @@ -96,5 +98,5 @@ return { -- FilterSeverity = { } } - --RenderingMethod = "ABuffer" -- alternative: "Framebuffer" + -- RenderingMethod = "ABuffer" -- alternative: "Framebuffer" } From d9fa55581f0e24a7c85669dca19ba6870a769b57 Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Jul 2017 20:10:35 -0600 Subject: [PATCH 186/192] changes from PR comments --- .gitignore | 5 +- data/scene/missions/juno/juno/juno.mod | 23 ++-- data/spice/naif0011.tls | 148 ------------------------ data/web/log/script.js | 2 +- data/web/log/style.css | 9 ++ modules/touch/ext/.vs/libTUIO2/v14/.suo | Bin 5632 -> 0 bytes modules/touch/include/TouchMarker.h | 4 +- modules/touch/src/TouchInteraction.cpp | 6 +- modules/touch/src/TouchMarker.cpp | 4 +- modules/touch/src/TuioEar.cpp | 12 +- modules/touch/touchmodule.cpp | 4 - openspace.cfg | 2 +- src/interaction/interactionmode.cpp | 5 + 13 files changed, 39 insertions(+), 185 deletions(-) delete mode 100644 data/spice/naif0011.tls delete mode 100644 modules/touch/ext/.vs/libTUIO2/v14/.suo diff --git a/.gitignore b/.gitignore index 2db24ce1fb..5306c5559c 100644 --- a/.gitignore +++ b/.gitignore @@ -118,7 +118,4 @@ data/spice/nh_kernels data/spice/OsirisRexKernels data/spice/plu055.bsp data/spice/Rosetta -data/spice/sat375.bsp -data/scene/lodglobes/saturn/Launcher.config -data/scene/lodglobes/mars/test_stats -data/scene/lodglobes/saturn/GDAL_cache_ESRI_Imagery_World_2d/ \ No newline at end of file +data/spice/sat375.bsp \ No newline at end of file diff --git a/data/scene/missions/juno/juno/juno.mod b/data/scene/missions/juno/juno/juno.mod index 12c2d45131..823c8f9339 100644 --- a/data/scene/missions/juno/juno/juno.mod +++ b/data/scene/missions/juno/juno/juno.mod @@ -126,19 +126,16 @@ return { Name = "JunoTrail", Parent = "JupiterBarycenter", Renderable = { - Type = "RenderableTrail", - Body = "JUNO", - Frame = "GALACTIC", - Observer = "JUPITER BARYCENTER", - RGB = { 0.70,0.50,0.20 }, - TropicalOrbitPeriod = 394250.0, - EarthOrbitRatio = 4.5, - DayLength = 9.9259, - TimeStamps = false, - Textures = { - Type = "simple", - Color = "textures/glare_blue.png", - }, + Type = "RenderableTrailTrajectory", + Translation = { + Type = "SpiceTranslation", + Body = "JUNO", + Observer = "JUPITER BARYCENTER" + }, + Color = { 0.70, 0.50, 0.20 }, + StartTime = "2016 JUN 28", + EndTime = "2016 APR 01", + SampleInterval = 3600 }, }, } diff --git a/data/spice/naif0011.tls b/data/spice/naif0011.tls deleted file mode 100644 index 58fcbcbd7f..0000000000 --- a/data/spice/naif0011.tls +++ /dev/null @@ -1,148 +0,0 @@ -KPL/LSK - - -LEAPSECONDS KERNEL FILE -=========================================================================== - -Modifications: --------------- - -2015, Jan. 5 NJB Modified file to account for the leapsecond that - will occur on June 30, 2015. - -2012, Jan. 5 NJB Modified file to account for the leapsecond that - will occur on June 30, 2012. - -2008, Jul. 7 NJB Modified file to account for the leapsecond that - will occur on December 31, 2008. - -2005, Aug. 3 NJB Modified file to account for the leapsecond that - will occur on December 31, 2005. - -1998, Jul 17 WLT Modified file to account for the leapsecond that - will occur on December 31, 1998. - -1997, Feb 22 WLT Modified file to account for the leapsecond that - will occur on June 30, 1997. - -1995, Dec 14 KSZ Corrected date of last leapsecond from 1-1-95 - to 1-1-96. - -1995, Oct 25 WLT Modified file to account for the leapsecond that - will occur on Dec 31, 1995. - -1994, Jun 16 WLT Modified file to account for the leapsecond on - June 30, 1994. - -1993, Feb. 22 CHA Modified file to account for the leapsecond on - June 30, 1993. - -1992, Mar. 6 HAN Modified file to account for the leapsecond on - June 30, 1992. - -1990, Oct. 8 HAN Modified file to account for the leapsecond on - Dec. 31, 1990. - - -Explanation: ------------- - -The contents of this file are used by the routine DELTET to compute the -time difference - -[1] DELTA_ET = ET - UTC - -the increment to be applied to UTC to give ET. - -The difference between UTC and TAI, - -[2] DELTA_AT = TAI - UTC - -is always an integral number of seconds. The value of DELTA_AT was 10 -seconds in January 1972, and increases by one each time a leap second -is declared. Combining [1] and [2] gives - -[3] DELTA_ET = ET - (TAI - DELTA_AT) - - = (ET - TAI) + DELTA_AT - -The difference (ET - TAI) is periodic, and is given by - -[4] ET - TAI = DELTA_T_A + K sin E - -where DELTA_T_A and K are constant, and E is the eccentric anomaly of the -heliocentric orbit of the Earth-Moon barycenter. Equation [4], which ignores -small-period fluctuations, is accurate to about 0.000030 seconds. - -The eccentric anomaly E is given by - -[5] E = M + EB sin M - -where M is the mean anomaly, which in turn is given by - -[6] M = M + M t - 0 1 - -where t is the number of ephemeris seconds past J2000. - -Thus, in order to compute DELTA_ET, the following items are necessary. - - DELTA_TA - K - EB - M0 - M1 - DELTA_AT after each leap second. - -The numbers, and the formulation, are taken from the following sources. - - 1) Moyer, T.D., Transformation from Proper Time on Earth to - Coordinate Time in Solar System Barycentric Space-Time Frame - of Reference, Parts 1 and 2, Celestial Mechanics 23 (1981), - 33-56 and 57-68. - - 2) Moyer, T.D., Effects of Conversion to the J2000 Astronomical - Reference System on Algorithms for Computing Time Differences - and Clock Rates, JPL IOM 314.5--942, 1 October 1985. - -The variable names used above are consistent with those used in the -Astronomical Almanac. - -\begindata - -DELTET/DELTA_T_A = 32.184 -DELTET/K = 1.657D-3 -DELTET/EB = 1.671D-2 -DELTET/M = ( 6.239996D0 1.99096871D-7 ) - -DELTET/DELTA_AT = ( 10, @1972-JAN-1 - 11, @1972-JUL-1 - 12, @1973-JAN-1 - 13, @1974-JAN-1 - 14, @1975-JAN-1 - 15, @1976-JAN-1 - 16, @1977-JAN-1 - 17, @1978-JAN-1 - 18, @1979-JAN-1 - 19, @1980-JAN-1 - 20, @1981-JUL-1 - 21, @1982-JUL-1 - 22, @1983-JUL-1 - 23, @1985-JUL-1 - 24, @1988-JAN-1 - 25, @1990-JAN-1 - 26, @1991-JAN-1 - 27, @1992-JUL-1 - 28, @1993-JUL-1 - 29, @1994-JUL-1 - 30, @1996-JAN-1 - 31, @1997-JUL-1 - 32, @1999-JAN-1 - 33, @2006-JAN-1 - 34, @2009-JAN-1 - 35, @2012-JUL-1 - 36, @2015-JUL-1 ) - -\begintext - - diff --git a/data/web/log/script.js b/data/web/log/script.js index fea743117f..ac198a1189 100644 --- a/data/web/log/script.js +++ b/data/web/log/script.js @@ -1,4 +1,4 @@ -var levels = ['debug', 'info', 'warning', 'error', 'fatal']; +var levels = ['trace', 'debug', 'info', 'warning', 'error', 'fatal']; var filterLevel = 0; function insertAfter(newNode, referenceNode) { diff --git a/data/web/log/style.css b/data/web/log/style.css index 3aa140b30e..80a17198ed 100644 --- a/data/web/log/style.css +++ b/data/web/log/style.css @@ -27,6 +27,15 @@ label { margin-right: 0.5em; } +.log-level-trace { + color: #eeeeee; + background-color: #aaaaaa; + border-bottom: 1px solid #eaeaea; +} +.log-level-trace td:first-child { + border-left: 10px solid #eaeaea; +} + .log-level-debug { background-color: #bbdda9; border-bottom: 1px solid #7bc142; diff --git a/modules/touch/ext/.vs/libTUIO2/v14/.suo b/modules/touch/ext/.vs/libTUIO2/v14/.suo deleted file mode 100644 index cc39013d5358149db3c8b246adf0aaf2dfa512c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5632 zcmeHL&ubGw6#h1~wMCE=O2FcwU@smN?9oFH#vTenO4HtQuuZE;P0}CPgcf?}LGa>5 zp=Vn?7wy%9M^O>rMn z;Dbr@;kZ160Z+d}JY?xGaE`e8j?3k;y8Cz&4WNrGFpE`QF2*p09NP_S$(2n*1pOyI zm;W0#a zhiq}9!dCY=j*w&XQg*1z=ot|I+bXTx{p~ei6<5FR0D9X3|1$qyJzh8YKg8JEseVY> zkpGU?L!L0Ni%NeR^WRY}+d0%#>Ko{k{I~Pgo~V7mpZB5%J?pdlLE9S^kbjkm`gSWO zMeEF`Z?ydGkB8n^b+8I+fz!?(6O4gI!1Kq+-lumq; z6sbIG9#Ju@nXx$A1@bPlFH5N4}thkmp6n-)OAm*-re=_o6_}Rs4wWFO+SxdA! z({5jXtLyF+xgh_Q0j+!UdB^O3^V}`hFw31!`)3+OKJ_Ong@aP&>6=Smziofqe|X{3 K-b=04=KUY%-t)5n diff --git a/modules/touch/include/TouchMarker.h b/modules/touch/include/TouchMarker.h index aafa79f8a7..5f9380daac 100644 --- a/modules/touch/include/TouchMarker.h +++ b/modules/touch/include/TouchMarker.h @@ -58,11 +58,11 @@ class TouchMarker : public properties::PropertyOwner bool initialize(); bool deinitialize(); - void render(const std::vector list); + void render(const std::vector& list); private: - void createVertexList(const std::vector list); + void createVertexList(const std::vector& list); properties::BoolProperty _visible; properties::FloatProperty _radiusSize; diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 1cf3788cac..135e7f0d44 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -78,7 +78,7 @@ TouchInteraction::TouchInteraction() , _friction("Friction", "Friction for different interactions (orbit, zoom, roll, pan)", glm::vec4(0.01, 0.025, 0.02, 0.02), glm::vec4(0.0), glm::vec4(0.2)) , _vel{ glm::dvec2(0.0), 0.0, 0.0, glm::dvec2(0.0) } - , _sensitivity{glm::dvec2(0.0808181818181818, 0.0454545454545455), 4.0, 2.75, glm::dvec2(0.0808181818181818, 0.0454545454545455) } + , _sensitivity{glm::dvec2(0.08, 0.045), 4.0, 2.75, glm::dvec2(0.08, 0.045) } , _centroid{ glm::dvec3(0.0) } , _projectionScaleFactor{ 1.000004 } // calculated with two vectors with known diff in length, then projDiffLength/diffLength. , _currentRadius{ 1.0 }, _slerpdT{ 1000 }, _numOfTests{ 0 }, _timeSlack{ 0.0 } @@ -412,8 +412,8 @@ void TouchInteraction::findSelectedNode(const std::vector& list) { // Interprets the input gesture to a specific interaction int TouchInteraction::interpretInteraction(const std::vector& list, const std::vector& lastProcessed) { glm::dvec3 lastCentroid = _centroid; - _centroid.x = std::accumulate(list.begin(), list.end(), 0.0f, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); - _centroid.y = std::accumulate(list.begin(), list.end(), 0.0f, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); + _centroid.x = std::accumulate(list.begin(), list.end(), 0.0, [](double x, const TuioCursor& c) { return x + c.getX(); }) / list.size(); + _centroid.y = std::accumulate(list.begin(), list.end(), 0.0, [](double y, const TuioCursor& c) { return y + c.getY(); }) / list.size(); // see if the distance between fingers changed - used in pan interpretation double dist = 0; diff --git a/modules/touch/src/TouchMarker.cpp b/modules/touch/src/TouchMarker.cpp index b86ac4c468..d257035ae8 100644 --- a/modules/touch/src/TouchMarker.cpp +++ b/modules/touch/src/TouchMarker.cpp @@ -93,7 +93,7 @@ bool TouchMarker::deinitialize() { return true; } -void TouchMarker::render(const std::vector list) { +void TouchMarker::render(const std::vector& list) { if (_visible && !list.empty()) { createVertexList(list); _shader->activate(); @@ -115,7 +115,7 @@ void TouchMarker::render(const std::vector list) { } } -void TouchMarker::createVertexList(const std::vector list) { +void TouchMarker::createVertexList(const std::vector& list) { _numFingers = list.size(); GLfloat vertexData[MAX_FINGERS]; int i = 0; diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index 7ac3b21861..e7a020b802 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -34,9 +34,6 @@ #include using namespace TUIO; -namespace { - const std::string _loggerCat = "TuioEar"; -} void TuioEar::addTuioObject(TuioObject *tobj) { } @@ -89,12 +86,15 @@ void TuioEar::removeTuioCursor(TuioCursor *tcur) { _removeList.push_back(tcur->getSessionID()); // Check if the cursor ID could be considered a tap + std::list& path = tcur->getPath(); + glm::dvec2 currPos = glm::dvec2(tcur->getX(), tcur->getY()); double dist = 0; for (const TuioPoint& p : tcur->getPath()) { - dist += glm::length(glm::dvec2(p.getX(), p.getY()) - glm::dvec2(tcur->getX(), tcur->getY())); + dist += glm::length(glm::dvec2(p.getX(), p.getY()) - currPos); } dist /= tcur->getPath().size(); - double heldTime = tcur->getPath().back().getTuioTime().getTotalMilliseconds() - tcur->getPath().front().getTuioTime().getTotalMilliseconds(); + + double heldTime = path.back().getTuioTime().getTotalMilliseconds() - path.front().getTuioTime().getTotalMilliseconds(); if (heldTime < 180 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) { _tapCo = TuioCursor(*tcur); _tap = true; @@ -111,12 +111,10 @@ void TuioEar::removeTuioBlob(TuioBlob *tblb) { } void TuioEar::refresh(TuioTime frameTime) { } // about every 15ms std::vector TuioEar::getInput() { - std::lock_guard lock(_mx); return _list; } bool TuioEar::tap() { - std::lock_guard lock(_mx); if (_tap) { _tap = false; return !_tap; diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 39a5b6c5d4..0d24b34aa6 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -40,10 +40,6 @@ using namespace TUIO; -namespace { - const std::string _loggerCat = "TouchModule"; -} - namespace openspace { bool TouchModule::hasNewInput() { diff --git a/openspace.cfg b/openspace.cfg index edc03f6f93..d09dde7818 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -13,7 +13,7 @@ return { -- SGCTConfig = sgct.config.single{1920, 1080}, -- A windowed 1920x1080 fullscreen - SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}, shared=true, name="WV_OBS_SPOUT1"}, + -- SGCTConfig = sgct.config.single{1920, 1080, border=false, windowPos={0,0}, shared=true, name="WV_OBS_SPOUT1"}, -- A 1k fisheye rendering -- SGCTConfig = sgct.config.fisheye{1024, 1024}, diff --git a/src/interaction/interactionmode.cpp b/src/interaction/interactionmode.cpp index c5624b551c..1c487230ec 100644 --- a/src/interaction/interactionmode.cpp +++ b/src/interaction/interactionmode.cpp @@ -263,8 +263,10 @@ OrbitalInteractionMode::MouseStates::MouseStates(double sensitivity, double velo {} void OrbitalInteractionMode::MouseStates::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) { +#ifdef OPENSPACE_MODULE_TOUCH_ENABLED ghoul::any t = property("Global Properties.Touch.TouchInteraction.TouchEvents")->get(); if (!*(ghoul::any_cast(&t))) { +#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED glm::dvec2 mousePosition = inputState.getMousePosition(); bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); @@ -333,7 +335,10 @@ void OrbitalInteractionMode::MouseStates::updateMouseStatesFromInput(const Input _localRollMouseState.previousPosition = mousePosition; _localRollMouseState.velocity.decelerate(deltaTime); } +#ifdef OPENSPACE_MODULE_TOUCH_ENABLED } +#endif // OPENSPACE_MODULE_TOUCH_ENABLED + } void OrbitalInteractionMode::MouseStates::setRotationalFriction(double friction) { From bca8af78c3667d6fa4dab0b5546780ad29f302fb Mon Sep 17 00:00:00 2001 From: Jonathan Bosson Date: Thu, 13 Jul 2017 20:15:58 -0600 Subject: [PATCH 187/192] build fix, cannot bind non-const lvalue reference --- modules/touch/src/TuioEar.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index e7a020b802..ae8e22efe9 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -86,7 +86,6 @@ void TuioEar::removeTuioCursor(TuioCursor *tcur) { _removeList.push_back(tcur->getSessionID()); // Check if the cursor ID could be considered a tap - std::list& path = tcur->getPath(); glm::dvec2 currPos = glm::dvec2(tcur->getX(), tcur->getY()); double dist = 0; for (const TuioPoint& p : tcur->getPath()) { @@ -94,7 +93,7 @@ void TuioEar::removeTuioCursor(TuioCursor *tcur) { } dist /= tcur->getPath().size(); - double heldTime = path.back().getTuioTime().getTotalMilliseconds() - path.front().getTuioTime().getTotalMilliseconds(); + double heldTime = tcur->getPath().back().getTuioTime().getTotalMilliseconds() - tcur->getPath().front().getTuioTime().getTotalMilliseconds(); if (heldTime < 180 && dist < 0.0004 && _list.size() == 1 && _removeList.size() == 1) { _tapCo = TuioCursor(*tcur); _tap = true; From 9a9fcf0ac11bbffb0c203d300c052be8b249083d Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Thu, 13 Jul 2017 20:16:01 -0600 Subject: [PATCH 188/192] Alex's recommended changes in pull #357. Add check for log directory existence and creation --- .../performance/performancemanager.h | 11 +++-- .../src/guiperformancecomponent.cpp | 2 + src/engine/configurationmanager_doc.inl | 6 ++- src/performance/performancemanager.cpp | 48 ++++++++++++++----- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/include/openspace/performance/performancemanager.h b/include/openspace/performance/performancemanager.h index 6033a1e4c7..21e7c64b27 100644 --- a/include/openspace/performance/performancemanager.h +++ b/include/openspace/performance/performancemanager.h @@ -60,20 +60,20 @@ public: void outputLogs(); - void writeData(std::ofstream& out, const std::vector data); + void writeData(std::ofstream& out, const std::vector& data); - const std::string formatLogName(std::string nodeName); + std::string formatLogName(std::string nodeName); void logDir(std::string dir); - std::string logDir(); + std::string logDir() const; void prefix(std::string prefix); - std::string prefix(); + std::string prefix() const; void enableLogging(); void disableLogging(); void toggleLogging(); void setLogging(bool enabled); - bool loggingEnabled(); + bool loggingEnabled() const; PerformanceLayout* performanceData(); private: @@ -92,6 +92,7 @@ private: size_t _tick; void tick(); + bool createLogDir(); }; } // namespace performance diff --git a/modules/onscreengui/src/guiperformancecomponent.cpp b/modules/onscreengui/src/guiperformancecomponent.cpp index 4e8771d726..86893cc93e 100644 --- a/modules/onscreengui/src/guiperformancecomponent.cpp +++ b/modules/onscreengui/src/guiperformancecomponent.cpp @@ -86,6 +86,8 @@ void GuiPerformanceComponent::render() { v = _outputLogs; ImGui::Checkbox("Output Logs", &v); OsEng.renderEngine().performanceManager()->setLogging(v); + // Need to catch if it's unsuccessful + v = OsEng.renderEngine().performanceManager()->loggingEnabled(); _outputLogs = v; ImGui::Spacing(); diff --git a/src/engine/configurationmanager_doc.inl b/src/engine/configurationmanager_doc.inl index 45c60c8868..9446e54a16 100644 --- a/src/engine/configurationmanager_doc.inl +++ b/src/engine/configurationmanager_doc.inl @@ -89,13 +89,15 @@ documentation::Documentation ConfigurationManager::Documentation() { { ConfigurationManager::PartLogDir, new StringVerifier, - "The directory for logs", + "The directory for logs." + "Default value is \"${BASE_PATH}\"", Optional::Yes }, { ConfigurationManager::PartLogPerformancePrefix, new StringVerifier, - "A string to prefix PerformanceMeasurement logfiles", + "A string to prefix PerformanceMeasurement logfiles." + "Default value is \"PM-\"", Optional::Yes }, { diff --git a/src/performance/performancemanager.cpp b/src/performance/performancemanager.cpp index 6368ee352e..beaa9cba0d 100644 --- a/src/performance/performancemanager.cpp +++ b/src/performance/performancemanager.cpp @@ -137,14 +137,12 @@ PerformanceManager::PerformanceManager() , _loggingEnabled(false) , _logDir(absPath("${BASE_PATH}")) , _prefix("PM-") - , _suffix("") , _ext("log") { - using ghoul::SharedMemory; PerformanceManager::createGlobalSharedMemory(); - SharedMemory sharedMemory(GlobalSharedMemoryName); + ghoul::SharedMemory sharedMemory(GlobalSharedMemoryName); sharedMemory.acquireLock(); OnExit([&](){sharedMemory.releaseLock();}); @@ -160,7 +158,7 @@ PerformanceManager::PerformanceManager() const int totalSize = sizeof(PerformanceLayout); LINFO("Create shared memory '" + localName + "' of " << totalSize << " bytes"); - if (SharedMemory::exists(localName)) { + if (ghoul::SharedMemory::exists(localName)) { throw ghoul::RuntimeError( "Shared Memory '" + localName + "' block already existed" ); @@ -247,14 +245,14 @@ void PerformanceManager::outputLogs() { } } -void PerformanceManager::writeData(std::ofstream& out, const std::vector data) { +void PerformanceManager::writeData(std::ofstream& out, const std::vector& data) { for (size_t i = 0; i < data.size() - 1; i++) { out << data[i] << ","; } out << data[data.size() - 1] << "\n"; } -const std::string PerformanceManager::formatLogName(std::string nodeName) { + std::string PerformanceManager::formatLogName(std::string nodeName) { // Replace any colons with dashes std::replace(nodeName.begin(), nodeName.end(), ':', '-'); return _logDir + "/" + _prefix + nodeName + _suffix + "." + _ext; @@ -264,7 +262,7 @@ void PerformanceManager::logDir(std::string dir) { _logDir = absPath(dir); } -std::string PerformanceManager::logDir() { +std::string PerformanceManager::logDir() const { return _logDir; } @@ -272,7 +270,7 @@ void PerformanceManager::prefix(std::string prefix) { _prefix = prefix; } -std::string PerformanceManager::prefix() { +std::string PerformanceManager::prefix() const { return _prefix; } @@ -285,13 +283,39 @@ void PerformanceManager::disableLogging() { } void PerformanceManager::toggleLogging() { - _loggingEnabled = !_loggingEnabled; + setLogging(!_loggingEnabled); } + void PerformanceManager::setLogging(bool enabled) { + // Create the log directory if it doesn't exist. Do it here, so that it + // only tests once each time output is enabled + if (enabled) { + // If it can't create the directory, it's not logging so set false + enabled = createLogDir(); + } + _loggingEnabled = enabled; } -bool PerformanceManager::loggingEnabled() { +bool PerformanceManager::createLogDir() { + // Done if it exists + ghoul::filesystem::Directory dir(_logDir); + if (FileSys.directoryExists(dir)) { + return true; + } + + // Error and set false if can't create + try { + FileSys.createDirectory(dir, ghoul::filesystem::FileSystem::Recursive::Yes); + } + catch (const ghoul::filesystem::FileSystem::FileSystemException& e) { + LERROR("Could not create log directory: " << e.message); + return false; + } + return true; +} + +bool PerformanceManager::loggingEnabled() const { return _loggingEnabled; } @@ -404,7 +428,9 @@ void PerformanceManager::storeScenePerformanceMeasurements( } _performanceMemory->releaseLock(); - if (_loggingEnabled && _tick == PerformanceLayout::NumberValues - 1) outputLogs(); + if (_loggingEnabled && _tick == PerformanceLayout::NumberValues - 1) { + outputLogs(); + } tick(); } From 4ecb98f06f562bacf93b257b0b9c6635a79234a6 Mon Sep 17 00:00:00 2001 From: Kalle Bladin Date: Fri, 14 Jul 2017 16:33:03 +0200 Subject: [PATCH 189/192] Feature/globe shading (#363) * Perform Oren Nayar diffuse shading on globes. * Remove unused propertyowner * Enable accurate normals for globes * Use property for accurate normals. * Correctly calculate height when scale is changed. * Auto update line endings to LF in main.cpp and openspaceengine.cpp * Clean up and comment * Convert shader indentation to spaces (Wooooops..). * Line endings * Line endings and small fixes * Line endings * Clean up --- Jenkinsfile | 160 +++---- modules/globebrowsing/CMakeLists.txt | 4 +- .../globebrowsing/globes/renderableglobe.cpp | 8 +- .../globebrowsing/globes/renderableglobe.h | 4 +- .../globebrowsing/rendering/chunkrenderer.cpp | 112 ++++- .../globebrowsing/rendering/chunkrenderer.h | 3 + .../rendering/layershadermanager.cpp | 13 +- modules/globebrowsing/shaders/blending.hglsl | 96 ++-- modules/globebrowsing/shaders/ellipsoid.hglsl | 60 +-- .../shaders/globalchunkedlodpatch_fs.glsl | 1 - .../shaders/globalchunkedlodpatch_vs.glsl | 36 +- .../globebrowsing/shaders/globeshading.hglsl | 61 +++ .../shaders/localchunkedlodpatch_fs.glsl | 1 - .../shaders/localchunkedlodpatch_vs.glsl | 19 +- .../shaders/texturetilemapping.hglsl | 435 +++++++++--------- modules/globebrowsing/shaders/tile.hglsl | 114 ++--- .../globebrowsing/shaders/tilefragcolor.hglsl | 182 ++++---- .../globebrowsing/shaders/tileheight.hglsl | 125 +++++ .../shaders/tilevertexheight.hglsl | 126 ----- .../shaders/tilevertexskirt.hglsl | 44 ++ openspace.cfg | 1 - 21 files changed, 908 insertions(+), 697 deletions(-) create mode 100644 modules/globebrowsing/shaders/globeshading.hglsl create mode 100644 modules/globebrowsing/shaders/tileheight.hglsl delete mode 100644 modules/globebrowsing/shaders/tilevertexheight.hglsl create mode 100644 modules/globebrowsing/shaders/tilevertexskirt.hglsl diff --git a/Jenkinsfile b/Jenkinsfile index 963a1b38ad..6bec006822 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,80 +1,80 @@ -def modules = [ - "base", - "debugging", - "fieldlines", - "galaxy", - "globebrowsing", - "iswa", - "kameleon", - "kameleonvolume", - "multiresvolume", - "newhorizons", - "onscreengui", - "space", - "toyvolume", - "volume" -]; - -def flags = "-DGHOUL_USE_DEVIL=OFF " - -for (module in modules) { - flags += "-DOPENSPACE_OPENSPACE_MODULE_" + module.toUpperCase() + "=ON " -} - -echo flags - -stage('Build') { - parallel linux: { - node('linux') { - timeout(time: 30, unit: 'MINUTES') { - checkout scm - sh 'git submodule update --init --recursive' - sh ''' - mkdir -p build - cd build - cmake .. ''' + - flags + ''' .. - make -j2 - ''' - } - } - }, - windows: { - node('windows') { - timeout(time: 30, unit: 'MINUTES') { - checkout scm - bat ''' - git submodule update --init --recursive - if not exist "build" mkdir "build" - cd build - cmake -G "Visual Studio 15 2017 Win64" .. ''' + - flags + ''' .. - msbuild.exe OpenSpace.sln /nologo /verbosity:minimal /m:2 /p:Configuration=Debug - ''' - } - } - }, - osx: { - node('osx') { - timeout(time: 30, unit: 'MINUTES') { - checkout scm - sh 'git submodule update --init --recursive' - sh ''' - export PATH=${PATH}:/usr/local/bin:/Applications/CMake.app/Contents/bin - export CMAKE_BUILD_TOOL=/Applications/CMake.app/Contents/bin/CMake - srcDir=$PWD - if [ ! -d ${srcDir} ]; then - mkdir ${srcDir} - fi - if [ ! -d ${srcDir}/build ]; then - mkdir ${srcDir}/build - fi - cd ${srcDir}/build - /Applications/CMake.app/Contents/bin/cmake -G Xcode ${srcDir} .. ''' + - flags + ''' - xcodebuild -quiet - ''' - } - } - } -} +def modules = [ + "base", + "debugging", + "fieldlines", + "galaxy", + "globebrowsing", + "iswa", + "kameleon", + "kameleonvolume", + "multiresvolume", + "newhorizons", + "onscreengui", + "space", + "toyvolume", + "volume" +]; + +def flags = "-DGHOUL_USE_DEVIL=OFF " + +for (module in modules) { + flags += "-DOPENSPACE_OPENSPACE_MODULE_" + module.toUpperCase() + "=ON " +} + +echo flags + +stage('Build') { + parallel linux: { + node('linux') { + timeout(time: 30, unit: 'MINUTES') { + checkout scm + sh 'git submodule update --init --recursive' + sh ''' + mkdir -p build + cd build + cmake .. ''' + + flags + ''' .. + make -j2 + ''' + } + } + }, + windows: { + node('windows') { + timeout(time: 30, unit: 'MINUTES') { + checkout scm + bat ''' + git submodule update --init --recursive + if not exist "build" mkdir "build" + cd build + cmake -G "Visual Studio 15 2017 Win64" .. ''' + + flags + ''' .. + msbuild.exe OpenSpace.sln /nologo /verbosity:minimal /m:2 /p:Configuration=Debug + ''' + } + } + }, + osx: { + node('osx') { + timeout(time: 30, unit: 'MINUTES') { + checkout scm + sh 'git submodule update --init --recursive' + sh ''' + export PATH=${PATH}:/usr/local/bin:/Applications/CMake.app/Contents/bin + export CMAKE_BUILD_TOOL=/Applications/CMake.app/Contents/bin/CMake + srcDir=$PWD + if [ ! -d ${srcDir} ]; then + mkdir ${srcDir} + fi + if [ ! -d ${srcDir}/build ]; then + mkdir ${srcDir}/build + fi + cd ${srcDir}/build + /Applications/CMake.app/Contents/bin/cmake -G Xcode ${srcDir} .. ''' + + flags + ''' + xcodebuild -quiet + ''' + } + } + } +} diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 57b8c92a56..2c30b6489e 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -218,7 +218,9 @@ set(SHADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/shaders/texturetilemapping.hglsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tile.hglsl ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tilefragcolor.hglsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tilevertexheight.hglsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tileheight.hglsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/tilevertexskirt.hglsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/globeshading.hglsl ) source_group("Shader Files" FILES ${SHADER_FILES}) diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index f8976b8f58..38c902841f 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -65,11 +65,12 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) BoolProperty("enabled", "Enabled", true), BoolProperty("performShading", "perform shading", true), BoolProperty("atmosphere", "atmosphere", false), + BoolProperty("useAccurateNormals", "useAccurateNormals", false), FloatProperty("lodScaleFactor", "lodScaleFactor",10.0f, 1.0f, 50.0f), - FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f) + FloatProperty("cameraMinHeight", "cameraMinHeight", 100.0f, 0.0f, 1000.0f), + FloatProperty("orenNayarRoughness", "orenNayarRoughness", 0.0f, 0.0f, 1.0f) }) , _debugPropertyOwner("Debug") - , _texturePropertyOwner("Textures") { setName("RenderableGlobe"); @@ -114,8 +115,10 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) addProperty(_generalProperties.isEnabled); addProperty(_generalProperties.atmosphereEnabled); addProperty(_generalProperties.performShading); + addProperty(_generalProperties.useAccurateNormals); addProperty(_generalProperties.lodScaleFactor); addProperty(_generalProperties.cameraMinHeight); + addProperty(_generalProperties.orenNayarRoughness); _debugPropertyOwner.addProperty(_debugProperties.saveOrThrowCamera); _debugPropertyOwner.addProperty(_debugProperties.showChunkEdges); @@ -138,6 +141,7 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _chunkedLodGlobe->notifyShaderRecompilation(); }; _generalProperties.atmosphereEnabled.onChange(notifyShaderRecompilation); + _generalProperties.useAccurateNormals.onChange(notifyShaderRecompilation); _generalProperties.performShading.onChange(notifyShaderRecompilation); _debugProperties.showChunkEdges.onChange(notifyShaderRecompilation); _debugProperties.showHeightResolution.onChange(notifyShaderRecompilation); diff --git a/modules/globebrowsing/globes/renderableglobe.h b/modules/globebrowsing/globes/renderableglobe.h index ee92df2197..d4c5071577 100644 --- a/modules/globebrowsing/globes/renderableglobe.h +++ b/modules/globebrowsing/globes/renderableglobe.h @@ -32,6 +32,7 @@ #include #include +#include namespace openspace { namespace globebrowsing { @@ -74,8 +75,10 @@ public: properties::BoolProperty isEnabled; properties::BoolProperty performShading; properties::BoolProperty atmosphereEnabled; + properties::BoolProperty useAccurateNormals; properties::FloatProperty lodScaleFactor; properties::FloatProperty cameraMinHeight; + properties::FloatProperty orenNayarRoughness; }; RenderableGlobe(const ghoul::Dictionary& dictionary); @@ -127,7 +130,6 @@ private: DebugProperties _debugProperties; GeneralProperties _generalProperties; properties::PropertyOwner _debugPropertyOwner; - properties::PropertyOwner _texturePropertyOwner; }; } // namespace globebrowsing diff --git a/modules/globebrowsing/rendering/chunkrenderer.cpp b/modules/globebrowsing/rendering/chunkrenderer.cpp index 7a35557cad..b8db58132e 100644 --- a/modules/globebrowsing/rendering/chunkrenderer.cpp +++ b/modules/globebrowsing/rendering/chunkrenderer.cpp @@ -112,6 +112,79 @@ ghoul::opengl::ProgramObject* ChunkRenderer::getActivatedProgramWithTileData( return programObject; } +void ChunkRenderer::setCommonUniforms(ghoul::opengl::ProgramObject& programObject, + const Chunk& chunk, const RenderData& data) +{ + glm::dmat4 modelTransform = chunk.owner().modelTransform(); + glm::dmat4 viewTransform = data.camera.combinedViewMatrix(); + glm::dmat4 modelViewTransform = viewTransform * modelTransform; + + const bool nightLayersActive = + !_layerManager->layerGroup(layergroupid::NightLayers).activeLayers().empty(); + const bool waterLayersActive = + !_layerManager->layerGroup(layergroupid::WaterMasks).activeLayers().empty(); + + if (nightLayersActive || + waterLayersActive || + chunk.owner().generalProperties().atmosphereEnabled || + chunk.owner().generalProperties().performShading) + { + glm::vec3 directionToSunWorldSpace = + glm::normalize(-data.modelTransform.translation); + glm::vec3 directionToSunCameraSpace = + (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); + programObject.setUniform( + "lightDirectionCameraSpace", -directionToSunCameraSpace); + } + + if (chunk.owner().generalProperties().performShading) { + programObject.setUniform( + "orenNayarRoughness", + chunk.owner().generalProperties().orenNayarRoughness); + } + + if (chunk.owner().generalProperties().useAccurateNormals) { + glm::dvec3 corner00 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(Quad::SOUTH_WEST)); + glm::dvec3 corner10 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(Quad::SOUTH_EAST)); + glm::dvec3 corner01 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(Quad::NORTH_WEST)); + glm::dvec3 corner11 = chunk.owner().ellipsoid().cartesianSurfacePosition( + chunk.surfacePatch().getCorner(Quad::NORTH_EAST)); + + // This is an assumption that the height tile has a resolution of 64 * 64 + // If it does not it will still produce "correct" normals. If the resolution is + // higher the shadows will be softer, if it is lower, pixels will be visible. + // Since default is 64 this will most likely work fine. + float tileDelta = 1.0f / 64.0f; + glm::vec3 deltaTheta0 = glm::vec3(corner10 - corner00) * tileDelta; + glm::vec3 deltaTheta1 = glm::vec3(corner11 - corner01) * tileDelta; + glm::vec3 deltaPhi0 = glm::vec3(corner01 - corner00) * tileDelta; + glm::vec3 deltaPhi1 = glm::vec3(corner11 - corner10) * tileDelta; + + // Transform to camera space + glm::mat3 modelViewTransformMat3 = glm::mat3(modelViewTransform); + deltaTheta0 = modelViewTransformMat3 * deltaTheta0; + deltaTheta1 = modelViewTransformMat3 * deltaTheta1; + deltaPhi0 = modelViewTransformMat3 * deltaPhi0; + deltaPhi1 = modelViewTransformMat3 * deltaPhi1; + + // Upload uniforms + programObject.setUniform("deltaTheta0", glm::length(deltaTheta0)); + programObject.setUniform("deltaTheta1", glm::length(deltaTheta1)); + programObject.setUniform("deltaPhi0", glm::length(deltaPhi0)); + programObject.setUniform("deltaPhi1", glm::length(deltaPhi1)); + programObject.setUniform("tileDelta", tileDelta); + } + + if (chunk.owner().generalProperties().performShading) { + programObject.setUniform( + "orenNayarRoughness", + chunk.owner().generalProperties().orenNayarRoughness); + } +} + void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& data){ ghoul::opengl::ProgramObject* programObject = getActivatedProgramWithTileData( @@ -159,16 +232,20 @@ void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& da _layerManager->layerGroup( layergroupid::WaterMasks).activeLayers().size() > 0 || chunk.owner().generalProperties().atmosphereEnabled || - chunk.owner().generalProperties().performShading) { - // This code temporary until real light sources can be implemented. - glm::vec3 directionToSunWorldSpace = - glm::normalize(-data.modelTransform.translation); - glm::vec3 directionToSunCameraSpace = - (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); + chunk.owner().generalProperties().performShading) + { programObject->setUniform("modelViewTransform", modelViewTransform); - programObject->setUniform( - "lightDirectionCameraSpace", -directionToSunCameraSpace); } + + if (chunk.owner().generalProperties().useAccurateNormals && + _layerManager->layerGroup(layergroupid::HeightLayers).activeLayers().size() > 0) + { + // Apply an extra scaling to the height if the object is scaled + programObject->setUniform( + "heightScale", static_cast(data.modelTransform.scale)); + } + + setCommonUniforms(*programObject, chunk, data); // OpenGL rendering settings glEnable(GL_DEPTH_TEST); @@ -235,21 +312,16 @@ void ChunkRenderer::renderChunkLocally(const Chunk& chunk, const RenderData& dat programObject->setUniform("patchNormalCameraSpace", patchNormalCameraSpace); programObject->setUniform("projectionTransform", data.camera.sgctInternal.projectionMatrix()); - if (_layerManager->layerGroup( - layergroupid::NightLayers).activeLayers().size() > 0 || - _layerManager->layerGroup( - layergroupid::WaterMasks).activeLayers().size() > 0 || - chunk.owner().generalProperties().atmosphereEnabled || - chunk.owner().generalProperties().performShading) - { - glm::vec3 directionToSunWorldSpace = - glm::normalize(-data.modelTransform.translation); - glm::vec3 directionToSunCameraSpace = - (viewTransform * glm::dvec4(directionToSunWorldSpace, 0)); + if (_layerManager->layerGroup(layergroupid::HeightLayers).activeLayers().size() > 0) { + // Apply an extra scaling to the height if the object is scaled programObject->setUniform( - "lightDirectionCameraSpace", -directionToSunCameraSpace); + "heightScale", static_cast(data.modelTransform.scale)); } + setCommonUniforms(*programObject, chunk, data); + + + // OpenGL rendering settings glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); diff --git a/modules/globebrowsing/rendering/chunkrenderer.h b/modules/globebrowsing/rendering/chunkrenderer.h index 90995a6f05..9caf680685 100644 --- a/modules/globebrowsing/rendering/chunkrenderer.h +++ b/modules/globebrowsing/rendering/chunkrenderer.h @@ -87,6 +87,9 @@ private: std::shared_ptr gpuLayerManager, const Chunk& chunk); + void setCommonUniforms(ghoul::opengl::ProgramObject& programObject, + const Chunk& chunk, const RenderData& data); + // shared pointer to a grid which can be the same for all rendered chunks. std::shared_ptr _grid; std::shared_ptr _layerManager; diff --git a/modules/globebrowsing/rendering/layershadermanager.cpp b/modules/globebrowsing/rendering/layershadermanager.cpp index 502dbbc150..bf51dddfc2 100644 --- a/modules/globebrowsing/rendering/layershadermanager.cpp +++ b/modules/globebrowsing/rendering/layershadermanager.cpp @@ -91,17 +91,22 @@ LayerShaderManager::LayerShaderPreprocessingData preprocessingData.layeredTextureInfo[i] = layeredTextureInfo; } - const auto& generalProps = globe.generalProperties(); - const auto& debugProps = globe.debugProperties(); + const RenderableGlobe::GeneralProperties& generalProps = globe.generalProperties(); + const RenderableGlobe::DebugProperties& debugProps = globe.debugProperties(); auto& pairs = preprocessingData.keyValuePairs; + pairs.emplace_back("useAccurateNormals", + std::to_string(generalProps.useAccurateNormals) + ); pairs.emplace_back("useAtmosphere", std::to_string(generalProps.atmosphereEnabled)); pairs.emplace_back("performShading", std::to_string(generalProps.performShading)); pairs.emplace_back("showChunkEdges", std::to_string(debugProps.showChunkEdges)); pairs.emplace_back("showHeightResolution", - std::to_string(debugProps.showHeightResolution)); + std::to_string(debugProps.showHeightResolution) + ); pairs.emplace_back("showHeightIntensities", - std::to_string(debugProps.showHeightIntensities)); + std::to_string(debugProps.showHeightIntensities) + ); pairs.emplace_back("defaultHeight", std::to_string(Chunk::DEFAULT_HEIGHT)); pairs.emplace_back("tilePaddingStart", diff --git a/modules/globebrowsing/shaders/blending.hglsl b/modules/globebrowsing/shaders/blending.hglsl index ce64c9ce84..6bcba5a4b3 100644 --- a/modules/globebrowsing/shaders/blending.hglsl +++ b/modules/globebrowsing/shaders/blending.hglsl @@ -25,29 +25,25 @@ #ifndef BLENDING_HGLSL #define BLENDING_HGLSL -vec4 blendNormal(vec4 oldColor, vec4 newColor) -{ - vec4 toReturn; - toReturn.rgb = - (newColor.rgb * newColor.a + oldColor.rgb * oldColor.a * (1 - newColor.a)) / - (newColor.a + oldColor.a * (1 - newColor.a)); - toReturn.a = newColor.a + oldColor.a * (1 - newColor.a); - return toReturn; +vec4 blendNormal(vec4 oldColor, vec4 newColor) { + vec4 toReturn; + toReturn.rgb = + (newColor.rgb * newColor.a + oldColor.rgb * oldColor.a * (1 - newColor.a)) / + (newColor.a + oldColor.a * (1 - newColor.a)); + toReturn.a = newColor.a + oldColor.a * (1 - newColor.a); + return toReturn; } -vec4 blendMultiply(vec4 oldColor, vec4 newColor) -{ - return oldColor * newColor; +vec4 blendMultiply(vec4 oldColor, vec4 newColor) { + return oldColor * newColor; } -vec4 blendAdd(vec4 oldColor, vec4 newColor) -{ - return oldColor + newColor; +vec4 blendAdd(vec4 oldColor, vec4 newColor) { + return oldColor + newColor; } -vec4 blendSubtract(vec4 oldColor, vec4 newColor) -{ - return oldColor - newColor; +vec4 blendSubtract(vec4 oldColor, vec4 newColor) { + return oldColor - newColor; } /* @@ -56,7 +52,7 @@ vec3 rgb2hsv(vec3 c) vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); //vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); //vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); + vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx); float d = q.x - min(q.w, q.y); @@ -72,15 +68,13 @@ vec3 hsv2rgb(vec3 c) } */ -vec3 hsl2rgb( in vec3 c ) -{ +vec3 hsl2rgb( in vec3 c ) { vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 ); return c.z + c.y * (rgb-0.5)*(1.0-abs(2.0*c.z-1.0)); } -vec3 HueShift (in vec3 Color, in float Shift) -{ +vec3 HueShift (in vec3 Color, in float Shift) { vec3 P = vec3(0.55735)*dot(vec3(0.55735),Color); vec3 U = Color-P; @@ -92,45 +86,44 @@ vec3 HueShift (in vec3 Color, in float Shift) return vec3(Color); } -vec3 rgb2hsl( in vec3 c ){ +vec3 rgb2hsl( in vec3 c ) { float h = 0.0; - float s = 0.0; - float l = 0.0; - float r = c.r; - float g = c.g; - float b = c.b; - float cMin = min( r, min( g, b ) ); - float cMax = max( r, max( g, b ) ); + float s = 0.0; + float l = 0.0; + float r = c.r; + float g = c.g; + float b = c.b; + float cMin = min( r, min( g, b ) ); + float cMax = max( r, max( g, b ) ); - l = ( cMax + cMin ) / 2.0; - if ( cMax > cMin ) { - float cDelta = cMax - cMin; + l = ( cMax + cMin ) / 2.0; + if ( cMax > cMin ) { + float cDelta = cMax - cMin; //s = l < .05 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); Original - s = l < .0 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); + s = l < .0 ? cDelta / ( cMax + cMin ) : cDelta / ( 2.0 - ( cMax + cMin ) ); - if ( r == cMax ) { - h = ( g - b ) / cDelta; - } else if ( g == cMax ) { - h = 2.0 + ( b - r ) / cDelta; - } else { - h = 4.0 + ( r - g ) / cDelta; - } + if ( r == cMax ) { + h = ( g - b ) / cDelta; + } else if ( g == cMax ) { + h = 2.0 + ( b - r ) / cDelta; + } else { + h = 4.0 + ( r - g ) / cDelta; + } - if ( h < 0.0) { - h += 6.0; - } - h = h / 6.0; - } - return vec3( h, s, l ); + if ( h < 0.0) { + h += 6.0; + } + h = h / 6.0; + } + return vec3( h, s, l ); } -vec3 rgb2hsv(vec3 c) -{ +vec3 rgb2hsv(vec3 c) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); //vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); //vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); - vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); + vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx); float d = q.x - min(q.w, q.y); @@ -138,8 +131,7 @@ vec3 rgb2hsv(vec3 c) return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); } -vec3 hsv2rgb(vec3 c) -{ +vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); diff --git a/modules/globebrowsing/shaders/ellipsoid.hglsl b/modules/globebrowsing/shaders/ellipsoid.hglsl index 19c702e2e2..7589bee984 100644 --- a/modules/globebrowsing/shaders/ellipsoid.hglsl +++ b/modules/globebrowsing/shaders/ellipsoid.hglsl @@ -26,62 +26,62 @@ #define ELLIPSOID_HGLSL struct PositionNormalPair { - vec3 position; - vec3 normal; + vec3 position; + vec3 normal; }; struct Intersection { bool intersects; float nearParameter;// Along ray - float farParameter; // Along ray + float farParameter; // Along ray }; vec3 geodeticSurfaceNormal(float latitude, float longitude) { - float cosLat = cos(latitude); - return vec3( - cosLat * cos(longitude), - cosLat * sin(longitude), - sin(latitude)); + float cosLat = cos(latitude); + return vec3( + cosLat * cos(longitude), + cosLat * sin(longitude), + sin(latitude)); } PositionNormalPair geodetic3ToCartesian( - float latitude, - float longitude, - float height, - vec3 radiiSquared) + float latitude, + float longitude, + float height, + vec3 radiiSquared) { - vec3 normal = geodeticSurfaceNormal(latitude, longitude); - vec3 k = radiiSquared * normal; - float gamma = sqrt(dot(k, normal)); - vec3 rSurface = k / gamma; - PositionNormalPair toReturn; - toReturn.position = rSurface + height * normal; - toReturn.normal = normal; - return toReturn; + vec3 normal = geodeticSurfaceNormal(latitude, longitude); + vec3 k = radiiSquared * normal; + float gamma = sqrt(dot(k, normal)); + vec3 rSurface = k / gamma; + PositionNormalPair toReturn; + toReturn.position = rSurface + height * normal; + toReturn.normal = normal; + return toReturn; } PositionNormalPair geodetic2ToCartesian(float latitude, float longitude, vec3 radiiSquared) { - // Position on surface : height = 0 - return geodetic3ToCartesian(latitude, longitude, 0, radiiSquared); + // Position on surface : height = 0 + return geodetic3ToCartesian(latitude, longitude, 0, radiiSquared); } vec3 latLonToCartesian(float latitude, float longitude, float radius) { - return radius * vec3( - cos(latitude) * cos(longitude), - cos(latitude) * sin(longitude), - sin(latitude)); + return radius * vec3( + cos(latitude) * cos(longitude), + cos(latitude) * sin(longitude), + sin(latitude)); } // // Assumes ellipsoid is at (0, 0, 0) // Intersection rayIntersectEllipsoid( - vec3 rayOrigin, - vec3 rayOriginSquared, - vec3 rayDirection, - vec3 oneOverEllipsoidRadiiSquared) + vec3 rayOrigin, + vec3 rayOriginSquared, + vec3 rayDirection, + vec3 oneOverEllipsoidRadiiSquared) { float a = dot(rayDirection * rayDirection, oneOverEllipsoidRadiiSquared); float b = 2.0 * dot(rayOrigin * rayDirection, oneOverEllipsoidRadiiSquared); diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl b/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl index 0bdf633ec6..9bdaa4fac7 100644 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl +++ b/modules/globebrowsing/shaders/globalchunkedlodpatch_fs.glsl @@ -36,4 +36,3 @@ Fragment getFragment() { frag.depth = fs_position.w; return frag; } - diff --git a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl index 86904a5db8..31dcdb1e15 100644 --- a/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/globalchunkedlodpatch_vs.glsl @@ -28,7 +28,8 @@ #include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> -#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexskirt.hglsl> uniform mat4 modelViewProjectionTransform; uniform mat4 modelViewTransform; @@ -39,6 +40,9 @@ uniform vec2 lonLatScalingFactor; uniform vec3 cameraPosition; uniform float chunkMinHeight; +uniform float distanceScaleFactor; +uniform int chunkLevel; + layout(location = 1) in vec2 in_uv; out vec2 fs_uv; @@ -47,16 +51,21 @@ out vec3 ellipsoidNormalCameraSpace; out LevelWeights levelWeights; out vec3 positionCameraSpace; -PositionNormalPair globalInterpolation() { +#if USE_ACCURATE_NORMALS +out vec3 ellipsoidTangentThetaCameraSpace; +out vec3 ellipsoidTangentPhiCameraSpace; +#endif //USE_ACCURATE_NORMALS + +PositionNormalPair globalInterpolation(vec2 uv) { vec2 lonLatInput; - lonLatInput.y = minLatLon.y + lonLatScalingFactor.y * in_uv.y; // Lat - lonLatInput.x = minLatLon.x + lonLatScalingFactor.x * in_uv.x; // Lon + lonLatInput.y = minLatLon.y + lonLatScalingFactor.y * uv.y; // Lat + lonLatInput.x = minLatLon.x + lonLatScalingFactor.x * uv.x; // Lon PositionNormalPair positionPairModelSpace = geodetic2ToCartesian(lonLatInput.y, lonLatInput.x, radiiSquared); return positionPairModelSpace; } void main() { - PositionNormalPair pair = globalInterpolation(); + PositionNormalPair pair = globalInterpolation(in_uv); float distToVertexOnEllipsoid = length(pair.position + pair.normal * chunkMinHeight - cameraPosition); @@ -70,11 +79,24 @@ void main() { levelWeights = getLevelWeights(levelInterpolationParameter); // Get the height value - float height = getTileVertexHeight(in_uv, levelWeights); + float height = getTileHeight(in_uv, levelWeights); // Apply skirts height -= getTileVertexSkirtLength(); - + +#if USE_ACCURATE_NORMALS + // Calculate tangents + // tileDelta is a step length (epsilon). Should be small enough for accuracy but not + // Too small for precision. 1 / 512 is good. + float tileDelta = 1.0f / 512.0f; + PositionNormalPair pair10 = globalInterpolation(in_uv + vec2(1.0, 0.0) * tileDelta); + PositionNormalPair pair01 = globalInterpolation(in_uv + vec2(0.0, 1.0) * tileDelta); + vec3 ellipsoidTangentTheta = normalize(pair10.position - pair.position); + vec3 ellipsoidTangentPhi = normalize(pair01.position - pair.position); + ellipsoidTangentThetaCameraSpace = mat3(modelViewTransform) * ellipsoidTangentTheta; + ellipsoidTangentPhiCameraSpace = mat3(modelViewTransform) * ellipsoidTangentPhi; +#endif // USE_ACCURATE_NORMALS + // Add the height in the direction of the normal pair.position += pair.normal * height; vec4 positionClippingSpace = modelViewProjectionTransform * vec4(pair.position, 1); diff --git a/modules/globebrowsing/shaders/globeshading.hglsl b/modules/globebrowsing/shaders/globeshading.hglsl new file mode 100644 index 0000000000..25b73cc827 --- /dev/null +++ b/modules/globebrowsing/shaders/globeshading.hglsl @@ -0,0 +1,61 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef GLOBESHADING_HGLSL +#define GLOBESHADING_HGLSL + +float orenNayarDiffuse( + vec3 lightDirection, + vec3 viewDirection, + vec3 surfaceNormal, + float roughness) +{ + // calculate intermediary values + float NdotL = dot(surfaceNormal, lightDirection); + float NdotV = dot(surfaceNormal, viewDirection); + + float angleVN = acos(NdotV); + float angleLN = acos(NdotL); + + float alpha = max(angleVN, angleLN); + float beta = min(angleVN, angleLN); + float gamma = dot( + viewDirection - surfaceNormal * dot(viewDirection, surfaceNormal), + lightDirection - surfaceNormal * dot(lightDirection, surfaceNormal) + ); + + float roughnessSquared = roughness * roughness; + + // calculate A and B + float A = 1.0 - 0.5 * (roughnessSquared / (roughnessSquared + 0.57)); + float B = 0.45 * (roughnessSquared / (roughnessSquared + 0.09)); + float C = sin(alpha) * tan(beta); + + // put it all together + float L1 = max(0.0, NdotL) * (A + B * max(0.0, gamma) * C); + + return L1; +} + +#endif // GLOBESHADING_HGLSL \ No newline at end of file diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl b/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl index 4601915b0c..300bfe9e31 100644 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl +++ b/modules/globebrowsing/shaders/localchunkedlodpatch_fs.glsl @@ -36,4 +36,3 @@ Fragment getFragment() { frag.depth = fs_position.w; return frag; } - diff --git a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl index 8665e88030..7952b116a3 100644 --- a/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl +++ b/modules/globebrowsing/shaders/localchunkedlodpatch_vs.glsl @@ -28,7 +28,8 @@ #include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> -#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tilevertexskirt.hglsl> uniform mat4 projectionTransform; @@ -41,6 +42,9 @@ uniform vec3 p11; uniform vec3 patchNormalCameraSpace; uniform float chunkMinHeight; +uniform float distanceScaleFactor; +uniform int chunkLevel; + layout(location = 1) in vec2 in_uv; out vec2 fs_uv; @@ -49,6 +53,11 @@ out vec3 ellipsoidNormalCameraSpace; out LevelWeights levelWeights; out vec3 positionCameraSpace; +#if USE_ACCURATE_NORMALS +out vec3 ellipsoidTangentThetaCameraSpace; +out vec3 ellipsoidTangentPhiCameraSpace; +#endif // USE_ACCURATE_NORMALS + vec3 bilinearInterpolation(vec2 uv) { vec3 p0 = (1 - uv.x) * p00 + uv.x * p10; vec3 p1 = (1 - uv.x) * p01 + uv.x * p11; @@ -75,7 +84,7 @@ void main() { levelWeights = getLevelWeights(levelInterpolationParameter); // Get the height value - float height = getTileVertexHeight(in_uv, levelWeights); + float height = getTileHeightScaled(in_uv, levelWeights); // Apply skirts height -= getTileVertexSkirtLength(); @@ -85,6 +94,12 @@ void main() { vec4 positionClippingSpace = projectionTransform * vec4(p, 1); + #if USE_ACCURATE_NORMALS + // Calculate tangents + ellipsoidTangentThetaCameraSpace = normalize(p10 - p00); + ellipsoidTangentPhiCameraSpace = normalize(p01 - p00); + #endif // USE_ACCURATE_NORMALS + // Write output fs_uv = in_uv; fs_position = z_normalization(positionClippingSpace); diff --git a/modules/globebrowsing/shaders/texturetilemapping.hglsl b/modules/globebrowsing/shaders/texturetilemapping.hglsl index 42b9bf0551..64f94dcca4 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.hglsl +++ b/modules/globebrowsing/shaders/texturetilemapping.hglsl @@ -27,6 +27,7 @@ #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/blending.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/globeshading.hglsl> // First layer type from LayerShaderManager is height map #define NUMLAYERS_HEIGHTMAP #{lastLayerIndexHeightLayers} + 1 @@ -58,53 +59,54 @@ // Other key value pairs used for settings #define USE_ATMOSPHERE #{useAtmosphere} +#define USE_ACCURATE_NORMALS #{useAccurateNormals} #define PERFORM_SHADING #{performShading} #define SHOW_CHUNK_EDGES #{showChunkEdges} #define SHOW_HEIGHT_RESOLUTION #{showHeightResolution} #define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities} float performLayerSettingsRGB(float currentValue, const LayerSettings settings) { - float newValue = currentValue; + float newValue = currentValue; - newValue = sign(newValue) * pow(abs(newValue), settings.gamma); - newValue = newValue * settings.multiplier; - newValue = newValue + settings.offset; + newValue = sign(newValue) * pow(abs(newValue), settings.gamma); + newValue = newValue * settings.multiplier; + newValue = newValue + settings.offset; - return newValue; + return newValue; } vec4 performLayerSettingsRGB(vec4 currentValue, const LayerSettings settings) { - vec4 newValue = vec4( - performLayerSettingsRGB(currentValue.r, settings), - performLayerSettingsRGB(currentValue.g, settings), - performLayerSettingsRGB(currentValue.b, settings), - currentValue.a); + vec4 newValue = vec4( + performLayerSettingsRGB(currentValue.r, settings), + performLayerSettingsRGB(currentValue.g, settings), + performLayerSettingsRGB(currentValue.b, settings), + currentValue.a); - return newValue; + return newValue; } float performLayerSettingsAlpha(float currentValue, const LayerSettings settings) { - float newValue = currentValue; - newValue = newValue * settings.opacity; - return newValue; + float newValue = currentValue; + newValue = newValue * settings.opacity; + return newValue; } vec4 performLayerSettingsAlpha(vec4 currentValue, const LayerSettings settings) { - vec4 newValue = currentValue; - newValue.a = performLayerSettingsAlpha(currentValue.a, settings); - return newValue; + vec4 newValue = currentValue; + newValue.a = performLayerSettingsAlpha(currentValue.a, settings); + return newValue; } float performLayerSettings(float currentValue, const LayerSettings settings) { - float newValue = performLayerSettingsRGB(currentValue, settings); - newValue = performLayerSettingsAlpha(newValue, settings); - return newValue; + float newValue = performLayerSettingsRGB(currentValue, settings); + newValue = performLayerSettingsAlpha(newValue, settings); + return newValue; } vec4 performLayerSettings(vec4 currentValue, const LayerSettings settings) { - vec4 newValue = performLayerSettingsRGB(currentValue, settings); - newValue = performLayerSettingsAlpha(newValue, settings); - return newValue; + vec4 newValue = performLayerSettingsRGB(currentValue, settings); + newValue = performLayerSettingsAlpha(newValue, settings); + return newValue; } @@ -112,32 +114,32 @@ vec4 performLayerSettings(vec4 currentValue, const LayerSettings settings) { #for i in 0..#{lastLayerIndex#{layerGroup}} vec4 getSample#{layerGroup}#{i}( - const vec2 uv, - const LevelWeights levelWeights, - const Layer #{layerGroup}[#{lastLayerIndex#{layerGroup}} + 1]) + const vec2 uv, + const LevelWeights levelWeights, + const Layer #{layerGroup}[#{lastLayerIndex#{layerGroup}} + 1]) { - vec4 color = vec4(0,0,0,1); - - // All tile layers are the same. Sample from texture + vec4 color = vec4(0,0,0,1); + + // All tile layers are the same. Sample from texture #if (#{#{layerGroup}#{i}LayerType} == 0) // DefaultTileLayer - color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); #elif (#{#{layerGroup}#{i}LayerType} == 1) // SingleImageTileLayer - color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); #elif (#{#{layerGroup}#{i}LayerType} == 2) // SizeReferenceTileLayer - color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); #elif (#{#{layerGroup}#{i}LayerType} == 3) // TemporalTileLayer - color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); #elif (#{#{layerGroup}#{i}LayerType} == 4) // TileIndexTileLayer - color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); #elif (#{#{layerGroup}#{i}LayerType} == 5) // ByIndexTileLayer - color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); #elif (#{#{layerGroup}#{i}LayerType} == 6) // ByLevelTileLayer - color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); + color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv); #elif (#{#{layerGroup}#{i}LayerType} == 7) // SolidColor - color.rgb = #{layerGroup}[#{i}].color; + color.rgb = #{layerGroup}[#{i}].color; #endif - return color; + return color; } #endfor @@ -148,24 +150,24 @@ vec4 getSample#{layerGroup}#{i}( vec4 blend#{layerGroup}#{i}(vec4 currentColor, vec4 newColor, float blendFactor) { #if (#{#{layerGroup}#{i}BlendMode} == 0) // Default, Normal - return blendNormal(currentColor, vec4(newColor.rgb, newColor.a * blendFactor)); + return blendNormal(currentColor, vec4(newColor.rgb, newColor.a * blendFactor)); #elif (#{#{layerGroup}#{i}BlendMode} == 1) // Multiply - return blendMultiply(currentColor, newColor * blendFactor); + return blendMultiply(currentColor, newColor * blendFactor); #elif (#{#{layerGroup}#{i}BlendMode} == 2) // Add - return blendAdd(currentColor, newColor * blendFactor); + return blendAdd(currentColor, newColor * blendFactor); #elif (#{#{layerGroup}#{i}BlendMode} == 3) // Subtract - return blendSubtract(currentColor, newColor * blendFactor); + return blendSubtract(currentColor, newColor * blendFactor); #elif (#{#{layerGroup}#{i}BlendMode} == 4) // Color - // Convert color to grayscale - float gray = (newColor.r + newColor.g + newColor.b) / 3.0; - - vec3 hsvCurrent = rgb2hsv(currentColor.rgb); - // Use gray from new color as value in hsv - vec3 hsvNew = vec3(hsvCurrent.x, hsvCurrent.y, gray); - vec3 rgbNew = hsv2rgb(hsvNew); + // Convert color to grayscale + float gray = (newColor.r + newColor.g + newColor.b) / 3.0; + + vec3 hsvCurrent = rgb2hsv(currentColor.rgb); + // Use gray from new color as value in hsv + vec3 hsvNew = vec3(hsvCurrent.x, hsvCurrent.y, gray); + vec3 rgbNew = hsv2rgb(hsvNew); - vec4 color = blendNormal(currentColor, vec4(rgbNew, newColor.a * blendFactor)); - return color; + vec4 color = blendNormal(currentColor, vec4(rgbNew, newColor.a * blendFactor)); + return color; #endif } @@ -178,18 +180,18 @@ vec4 blend#{layerGroup}#{i}(vec4 currentColor, vec4 newColor, float blendFactor) vec4 performAdjustment#{layerGroup}#{i}(vec4 currentColor, const LayerAdjustment adjustment) { #if (#{#{layerGroup}#{i}LayerAdjustmentType} == 0) // Default, None - return currentColor; + return currentColor; #elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 1) // ChromaKey - if (distance(currentColor.rgb, adjustment.chromaKeyColor) <= adjustment.chromaKeyTolerance) { - return vec4(0,0,0,0); - } - else { - return currentColor; - } + if (distance(currentColor.rgb, adjustment.chromaKeyColor) <= adjustment.chromaKeyTolerance) { + return vec4(0,0,0,0); + } + else { + return currentColor; + } #elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 2) // TransferFunction - return currentColor; + return currentColor; #else - return currentColor; + return currentColor; #endif } @@ -197,234 +199,241 @@ vec4 performAdjustment#{layerGroup}#{i}(vec4 currentColor, const LayerAdjustment #endfor float calculateUntransformedHeight( - vec2 uv, - LevelWeights levelWeights, - const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { + vec2 uv, + LevelWeights levelWeights, + const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { - float height = 0; + float height = 0; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // HEIGHTMAP_BLENDING_ENABLED - - #for i in 0..#{lastLayerIndexHeightLayers} - { - vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); - colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); - height = colorSample.r; + + #for i in 0..#{lastLayerIndexHeightLayers} + { + vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); + colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); + height = colorSample.r; - height = performLayerSettings(height, HeightLayers[#{i}].settings); - } - #endfor - return height; + height = performLayerSettings(height, HeightLayers[#{i}].settings); + } + #endfor + return height; } float calculateHeight( - vec2 uv, - LevelWeights levelWeights, - const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { + vec2 uv, + LevelWeights levelWeights, + const Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { - float height = 0; + float height = 0; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // HEIGHTMAP_BLENDING_ENABLED - - #for i in 0..#{lastLayerIndexHeightLayers} - { - vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); - colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); - float untransformedHeight = colorSample.r; + + #for i in 0..#{lastLayerIndexHeightLayers} + { + vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); + colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); + float untransformedHeight = colorSample.r; - float heightSample = getTransformedTexVal(HeightLayers[#{i}].depthTransform, untransformedHeight); - if (heightSample > -100000) { - heightSample = performLayerSettings(heightSample, HeightLayers[#{i}].settings); - height = heightSample; - } - } - #endfor - return height; + float heightSample = getTransformedTexVal(HeightLayers[#{i}].depthTransform, untransformedHeight); + if (heightSample > -100000) { + heightSample = performLayerSettings(heightSample, HeightLayers[#{i}].settings); + height = heightSample; + } + } + #endfor + return height; } vec4 calculateColor( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer ColorLayers[NUMLAYERS_COLORTEXTURE]) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer ColorLayers[NUMLAYERS_COLORTEXTURE]) { - vec4 color = currentColor; + vec4 color = currentColor; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !COLORTEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // COLORTEXTURE_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexColorLayers} - { - vec4 colorSample = getSampleColorLayers#{i}(uv, levelWeights, ColorLayers); - colorSample = performAdjustmentColorLayers#{i}(colorSample, ColorLayers[#{i}].adjustment); - colorSample = performLayerSettings(colorSample, ColorLayers[#{i}].settings); + #for i in 0..#{lastLayerIndexColorLayers} + { + vec4 colorSample = getSampleColorLayers#{i}(uv, levelWeights, ColorLayers); + colorSample = performAdjustmentColorLayers#{i}(colorSample, ColorLayers[#{i}].adjustment); + colorSample = performLayerSettings(colorSample, ColorLayers[#{i}].settings); - color = blendColorLayers#{i}(color, colorSample, 1.0); - } - #endfor + color = blendColorLayers#{i}(color, colorSample, 1.0); + } + #endfor - return color; + return color; } float gridDots(vec2 uv, vec2 gridResolution){ - vec2 uvVertexSpace = fract((gridResolution) * uv) + 0.5; + vec2 uvVertexSpace = fract((gridResolution) * uv) + 0.5; - vec2 uvDotSpace = abs(2*(uvVertexSpace-0.5)); - return 1-length(1-uvDotSpace); + vec2 uvDotSpace = abs(2*(uvVertexSpace-0.5)); + return 1-length(1-uvDotSpace); } vec4 calculateDebugColor(vec2 uv, vec4 fragPos, vec2 vertexResolution){ - vec2 uvVertexSpace = fract(vertexResolution * uv); - vec3 colorUv = vec3(0.3*uv.x, 0.3*uv.y, 0); - vec3 colorDistance = vec3(0, 0, min( 0.4*log(fragPos.w) - 3.9, 1)); - vec3 colorVertex = (1.0-length(uvVertexSpace)) * vec3(0.5); - vec3 colorSum = colorUv + colorDistance + colorVertex; - return vec4(0.5 * colorSum, 1); + vec2 uvVertexSpace = fract(vertexResolution * uv); + vec3 colorUv = vec3(0.3*uv.x, 0.3*uv.y, 0); + vec3 colorDistance = vec3(0, 0, min( 0.4*log(fragPos.w) - 3.9, 1)); + vec3 colorVertex = (1.0-length(uvVertexSpace)) * vec3(0.5); + vec3 colorSum = colorUv + colorDistance + colorVertex; + return vec4(0.5 * colorSum, 1); } float tileResolution(vec2 tileUV, const ChunkTile chunkTile){ - vec2 heightResolution = textureSize(chunkTile.textureSampler, 0); - vec2 uv = TileUVToTextureSamplePosition(chunkTile, tileUV); - return gridDots(uv, heightResolution); + vec2 heightResolution = textureSize(chunkTile.textureSampler, 0); + vec2 uv = TileUVToTextureSamplePosition(chunkTile, tileUV); + return gridDots(uv, heightResolution); } vec4 calculateNight( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer NightLayers[NUMLAYERS_NIGHTTEXTURE], - const vec3 ellipsoidNormalCameraSpace, - const vec3 lightDirectionCameraSpace) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer NightLayers[NUMLAYERS_NIGHTTEXTURE], + const vec3 ellipsoidNormalCameraSpace, + const vec3 lightDirectionCameraSpace) { - vec4 nightColor = vec4(0,0,0,0); - vec4 color = currentColor; + vec4 nightColor = vec4(0,0,0,0); + vec4 color = currentColor; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !NIGHTTEXTURE_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // NIGHTTEXTURE_BLENDING_ENABLED - vec3 n = normalize(ellipsoidNormalCameraSpace); - vec3 l = lightDirectionCameraSpace; - float cosineFactor = clamp(dot(l, normalize(n + 0.15 * l)) * 3 , 0, 1); - - #for i in 0..#{lastLayerIndexNightLayers} - { - vec4 colorSample = getSampleNightLayers#{i}(uv, levelWeights, NightLayers); - colorSample = performAdjustmentNightLayers#{i}(colorSample, NightLayers[#{i}].adjustment); - colorSample = performLayerSettings(colorSample, NightLayers[#{i}].settings); + vec3 n = normalize(ellipsoidNormalCameraSpace); + vec3 l = lightDirectionCameraSpace; + float cosineFactor = clamp(dot(l, normalize(n + 0.15 * l)) * 3 , 0, 1); + + #for i in 0..#{lastLayerIndexNightLayers} + { + vec4 colorSample = getSampleNightLayers#{i}(uv, levelWeights, NightLayers); + colorSample = performAdjustmentNightLayers#{i}(colorSample, NightLayers[#{i}].adjustment); + colorSample = performLayerSettings(colorSample, NightLayers[#{i}].settings); - float adjustedAlpha = cosineFactor * colorSample.a; - // Filter to night side - vec4 newColor = vec4(cosineFactor * colorSample.xyz, adjustedAlpha); + float adjustedAlpha = cosineFactor * colorSample.a; + // Filter to night side + vec4 newColor = vec4(cosineFactor * colorSample.xyz, adjustedAlpha); - color = blendNightLayers#{i}(currentColor, newColor, adjustedAlpha); - } - #endfor + color = blendNightLayers#{i}(currentColor, newColor, adjustedAlpha); + } + #endfor - return color; + return color; } vec4 calculateShadedColor( - const vec4 currentColor, - const vec3 ellipsoidNormalCameraSpace, - const vec3 lightDirectionCameraSpace) { + const vec4 currentColor, + const vec3 ellipsoidNormalCameraSpace, + const vec3 lightDirectionCameraSpace, + const vec3 viewDirectionCameraSpace, + float roughness) +{ + vec3 shadedColor = currentColor.rgb * 0.05; - vec3 shadedColor = currentColor.rgb * 0.05; + vec3 n = normalize(ellipsoidNormalCameraSpace); + vec3 l = lightDirectionCameraSpace; + + float power = orenNayarDiffuse( + -lightDirectionCameraSpace, + viewDirectionCameraSpace, + ellipsoidNormalCameraSpace, + roughness); - vec3 n = normalize(ellipsoidNormalCameraSpace); - vec3 l = lightDirectionCameraSpace; - - float cosineFactor = pow(clamp(dot(-l, n), 0, 1), 0.8); - - // Blend shaded color with base color - vec4 color = vec4(cosineFactor * currentColor.xyz + (1 - cosineFactor) * shadedColor, currentColor.a); - return color; + power = max(smoothstep(0.0f, 0.1f, max(dot(-l, n), 0.0f)) * power, 0.0f); + + vec4 color = vec4(shadedColor + currentColor.rgb * power, currentColor.a); + return color; } vec4 calculateOverlay( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer Overlays[NUMLAYERS_OVERLAY]) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer Overlays[NUMLAYERS_OVERLAY]) { - vec4 color = currentColor; + vec4 color = currentColor; - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !OVERLAY_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // OVERLAY_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexOverlays} - { - vec4 colorSample = getSampleOverlays#{i}(uv, levelWeights, Overlays); - colorSample = performAdjustmentOverlays#{i}(colorSample, Overlays[#{i}].adjustment); + #for i in 0..#{lastLayerIndexOverlays} + { + vec4 colorSample = getSampleOverlays#{i}(uv, levelWeights, Overlays); + colorSample = performAdjustmentOverlays#{i}(colorSample, Overlays[#{i}].adjustment); - colorSample = performLayerSettings(colorSample, Overlays[#{i}].settings); + colorSample = performLayerSettings(colorSample, Overlays[#{i}].settings); - color = blendNormal(color, colorSample); - color = blendOverlays#{i}(color, colorSample, 1.0); - } - #endfor + color = blendNormal(color, colorSample); + color = blendOverlays#{i}(color, colorSample, 1.0); + } + #endfor - return color; + return color; } vec4 calculateWater( - const vec4 currentColor, - const vec2 uv, - LevelWeights levelWeights, - const Layer WaterMasks[NUMLAYERS_WATERMASK], - const vec3 ellipsoidNormalCameraSpace, - const vec3 lightDirectionCameraSpace, - const vec3 positionCameraSpace) { + const vec4 currentColor, + const vec2 uv, + LevelWeights levelWeights, + const Layer WaterMasks[NUMLAYERS_WATERMASK], + const vec3 ellipsoidNormalCameraSpace, + const vec3 lightDirectionCameraSpace, + const vec3 positionCameraSpace) { - vec4 waterColor = vec4(0,0,0,0); + vec4 waterColor = vec4(0,0,0,0); - // The shader compiler will remove unused code when variables are multiplied by - // a constant 0 + // The shader compiler will remove unused code when variables are multiplied by + // a constant 0 #if !WATERMASK_BLENDING_ENABLED - levelWeights = getDefaultLevelWeights(); + levelWeights = getDefaultLevelWeights(); #endif // WATERMASK_BLENDING_ENABLED - #for i in 0..#{lastLayerIndexWaterMasks} - { - vec4 colorSample = getSampleWaterMasks#{i}(uv, levelWeights, WaterMasks); - colorSample = performAdjustmentWaterMasks#{i}(colorSample, WaterMasks[#{i}].adjustment); + #for i in 0..#{lastLayerIndexWaterMasks} + { + vec4 colorSample = getSampleWaterMasks#{i}(uv, levelWeights, WaterMasks); + colorSample = performAdjustmentWaterMasks#{i}(colorSample, WaterMasks[#{i}].adjustment); - colorSample = performLayerSettingsAlpha(colorSample, WaterMasks[#{i}].settings); - colorSample.a = performLayerSettingsRGB(colorSample.a, WaterMasks[#{i}].settings); + colorSample = performLayerSettingsAlpha(colorSample, WaterMasks[#{i}].settings); + colorSample.a = performLayerSettingsRGB(colorSample.a, WaterMasks[#{i}].settings); - waterColor = blendWaterMasks#{i}(waterColor, colorSample, 1.0); - } - #endfor + waterColor = blendWaterMasks#{i}(waterColor, colorSample, 1.0); + } + #endfor - vec3 directionToFragmentCameraSpace = normalize(positionCameraSpace - vec3(0, 0, 0)); - vec3 reflectionDirectionCameraSpace = reflect(lightDirectionCameraSpace, ellipsoidNormalCameraSpace); - float cosineFactor = clamp(dot(-reflectionDirectionCameraSpace, directionToFragmentCameraSpace), 0, 1); - cosineFactor = pow(cosineFactor, 100); + vec3 directionToFragmentCameraSpace = normalize(positionCameraSpace - vec3(0, 0, 0)); + vec3 reflectionDirectionCameraSpace = reflect(lightDirectionCameraSpace, ellipsoidNormalCameraSpace); + float cosineFactor = clamp(dot(-reflectionDirectionCameraSpace, directionToFragmentCameraSpace), 0, 1); + cosineFactor = pow(cosineFactor, 100); - vec3 specularColor = vec3(1, 1, 1); - float specularIntensity = 0.4; + vec3 specularColor = vec3(1, 1, 1); + float specularIntensity = 0.4; - vec3 specularTotal = specularColor * cosineFactor * specularIntensity * waterColor.a; + vec3 specularTotal = specularColor * cosineFactor * specularIntensity * waterColor.a; - //return blendNormal(currentColor, waterColor); - return currentColor + vec4(specularTotal, 1); + //return blendNormal(currentColor, waterColor); + return currentColor + vec4(specularTotal, 1); } #endif // TEXTURETILEMAPPING_HGLSL diff --git a/modules/globebrowsing/shaders/tile.hglsl b/modules/globebrowsing/shaders/tile.hglsl index bc93dfcf58..922e261ee8 100644 --- a/modules/globebrowsing/shaders/tile.hglsl +++ b/modules/globebrowsing/shaders/tile.hglsl @@ -32,11 +32,11 @@ #define TILE_PIXEL_SIZE_DIFFERENCE #{tilePaddingSizeDiff} vec4 patchBorderOverlay(vec2 uv, vec3 borderColor, float borderSize) { - vec2 uvOffset = uv - vec2(0.5); - float thres = 0.5 - borderSize/2; - bool isBorder = abs(uvOffset.x) > thres || abs(uvOffset.y) > thres; - vec3 color = isBorder ? borderColor : vec3(0); - return vec4(color, 0); + vec2 uvOffset = uv - vec2(0.5); + float thres = 0.5 - borderSize/2; + bool isBorder = abs(uvOffset.x) > thres || abs(uvOffset.y) > thres; + vec3 color = isBorder ? borderColor : vec3(0); + return vec4(color, 0); } @@ -50,11 +50,11 @@ struct TileDepthTransform { }; float getTransformedTexVal(const TileDepthTransform transform, const float val){ - return transform.depthOffset + transform.depthScale * val; + return transform.depthOffset + transform.depthScale * val; } vec4 getTransformedTexVal(const TileDepthTransform transform, const vec4 val){ - return transform.depthOffset + transform.depthScale * val; + return transform.depthOffset + transform.depthScale * val; } ///////////////////////////////////////////////////////////////////// @@ -71,30 +71,30 @@ struct TileUvTransform { // ChunkTile // ///////////////////////////////////////////////////////////////////// struct ChunkTile { - sampler2D textureSampler; - TileUvTransform uvTransform; + sampler2D textureSampler; + TileUvTransform uvTransform; }; vec2 compensateSourceTextureSampling(vec2 startOffset, vec2 sizeDiff, const ChunkTile chunkTile, vec2 tileUV){ - ivec2 resolution = textureSize(chunkTile.textureSampler, 0); + ivec2 resolution = textureSize(chunkTile.textureSampler, 0); - vec2 sourceSize = vec2(resolution) + sizeDiff; - vec2 currentSize = vec2(resolution); - vec2 sourceToCurrentSize = currentSize / sourceSize; - tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize); - return tileUV; + vec2 sourceSize = vec2(resolution) + sizeDiff; + vec2 currentSize = vec2(resolution); + vec2 sourceToCurrentSize = currentSize / sourceSize; + tileUV = sourceToCurrentSize * (tileUV - startOffset / sourceSize); + return tileUV; } vec2 TileUVToTextureSamplePosition(const ChunkTile chunkTile, vec2 tileUV){ - vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; - uv = compensateSourceTextureSampling(TILE_PIXEL_START_OFFSET, TILE_PIXEL_SIZE_DIFFERENCE, chunkTile, uv); - return uv; + vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; + uv = compensateSourceTextureSampling(TILE_PIXEL_START_OFFSET, TILE_PIXEL_SIZE_DIFFERENCE, chunkTile, uv); + return uv; } vec4 getTexVal(const ChunkTile chunkTile, vec2 tileUV){ - vec2 samplePosition = TileUVToTextureSamplePosition(chunkTile, tileUV); - vec4 texVal = texture(chunkTile.textureSampler, samplePosition); - return texVal; + vec2 samplePosition = TileUVToTextureSamplePosition(chunkTile, tileUV); + vec4 texVal = texture(chunkTile.textureSampler, samplePosition); + return texVal; } @@ -103,67 +103,67 @@ vec4 getTexVal(const ChunkTile chunkTile, vec2 tileUV){ // Chunk Tile Pile // ///////////////////////////////////////////////////////////////////// struct ChunkTilePile { - ChunkTile chunkTile0; - ChunkTile chunkTile1; - ChunkTile chunkTile2; + ChunkTile chunkTile0; + ChunkTile chunkTile1; + ChunkTile chunkTile2; }; struct LayerSettings { - float opacity; - float gamma; - float multiplier; - float offset; - float valueBlending; + float opacity; + float gamma; + float multiplier; + float offset; + float valueBlending; }; struct LayerAdjustment { - vec3 chromaKeyColor; - float chromaKeyTolerance; + vec3 chromaKeyColor; + float chromaKeyTolerance; }; struct Layer { - ChunkTilePile pile; - TileDepthTransform depthTransform; - LayerSettings settings; - LayerAdjustment adjustment; - - // Other layer type properties stuff - vec3 color; + ChunkTilePile pile; + TileDepthTransform depthTransform; + LayerSettings settings; + LayerAdjustment adjustment; + + // Other layer type properties stuff + vec3 color; }; struct LevelWeights { - float w1; - float w2; - float w3; + float w1; + float w2; + float w3; }; float getLevelInterpolationParameter(int chunkLevel, float distanceScaleFactor, float distToVertexOnEllipsoid){ - float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; - float desiredLevel = log2(projectedScaleFactor); - return chunkLevel - desiredLevel; + float projectedScaleFactor = distanceScaleFactor / distToVertexOnEllipsoid; + float desiredLevel = log2(projectedScaleFactor); + return chunkLevel - desiredLevel; } LevelWeights getLevelWeights(float levelInterpolationParameter){ - LevelWeights levelWeights; - levelWeights.w1 = clamp(1 - levelInterpolationParameter, 0 , 1); - levelWeights.w2 = (clamp(levelInterpolationParameter, 0 , 1) - clamp(levelInterpolationParameter - 1, 0 , 1)); - levelWeights.w3 = clamp(levelInterpolationParameter - 1, 0 , 1); - return levelWeights; + LevelWeights levelWeights; + levelWeights.w1 = clamp(1 - levelInterpolationParameter, 0 , 1); + levelWeights.w2 = (clamp(levelInterpolationParameter, 0 , 1) - clamp(levelInterpolationParameter - 1, 0 , 1)); + levelWeights.w3 = clamp(levelInterpolationParameter - 1, 0 , 1); + return levelWeights; } LevelWeights getDefaultLevelWeights(){ - LevelWeights levelWeights; - levelWeights.w1 = 1; - levelWeights.w2 = 0; - levelWeights.w3 = 0; - return levelWeights; + LevelWeights levelWeights; + levelWeights.w1 = 1; + levelWeights.w2 = 0; + levelWeights.w3 = 0; + return levelWeights; } vec4 getTexVal(const ChunkTilePile chunkTilePile, const LevelWeights w, const vec2 uv){ - return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv) + - w.w2 * getTexVal(chunkTilePile.chunkTile1, uv) + - w.w3 * getTexVal(chunkTilePile.chunkTile2, uv); + return w.w1 * getTexVal(chunkTilePile.chunkTile0, uv) + + w.w2 * getTexVal(chunkTilePile.chunkTile1, uv) + + w.w3 * getTexVal(chunkTilePile.chunkTile2, uv); } diff --git a/modules/globebrowsing/shaders/tilefragcolor.hglsl b/modules/globebrowsing/shaders/tilefragcolor.hglsl index e1dca0d4a9..c3e377a99a 100644 --- a/modules/globebrowsing/shaders/tilefragcolor.hglsl +++ b/modules/globebrowsing/shaders/tilefragcolor.hglsl @@ -27,6 +27,7 @@ #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/texturetilemapping.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/tileheight.hglsl> #include "PowerScaling/powerScaling_fs.hglsl" @@ -58,7 +59,11 @@ uniform vec2 vertexResolution; #endif // USE_ATMOSPHERE #if USE_NIGHTTEXTURE || USE_WATERMASK || USE_ATMOSPHERE || PERFORM_SHADING - uniform vec3 lightDirectionCameraSpace; + uniform vec3 lightDirectionCameraSpace; +#endif + +#if PERFORM_SHADING + uniform float orenNayarRoughness; #endif in vec4 fs_position; @@ -66,144 +71,123 @@ in vec2 fs_uv; in vec3 ellipsoidNormalCameraSpace; in vec3 positionCameraSpace; +#if USE_ACCURATE_NORMALS +in vec3 ellipsoidTangentThetaCameraSpace; +in vec3 ellipsoidTangentPhiCameraSpace; +#endif // USE_ACCURATE_NORMALS // levelInterpolationParameter is used to interpolate between a tile and its parent tiles // The value increases with the distance from the vertex (or fragment) to the camera in LevelWeights levelWeights; - -///////////////////////////////////////////////////////////////////// - -// The heightmaps is only used in the fragment shader visually debugging -// the alignment and resolution of the heightmaps - -#if USE_HEIGHTMAP -uniform Layer HeightLayers[NUMLAYERS_HEIGHTMAP]; -#endif // USE_HEIGHTMAP - -float getUntransformedTileVertexHeight(vec2 uv, LevelWeights levelWeights){ - float height = CHUNK_DEFAULT_HEIGHT; - -#if USE_HEIGHTMAP - // Calculate desired level based on distance to the vertex on the ellipsoid - // Before any heightmapping is done - height = calculateUntransformedHeight( - uv, - levelWeights, // Variable to determine which texture to sample from - HeightLayers); // Three textures to sample from - -#endif // USE_HEIGHTMAP - - return height; -} - -///////////////////////////////////////////////////////////////////// - - - - /** * This method defines the fragment color pipeline which is used in both * the local and global chunk rendering. * */ -vec4 getTileFragColor(){ +vec4 getTileFragColor() { - vec4 color = vec4(0.3,0.3,0.3,1); + vec4 color = vec4(0.3,0.3,0.3,1); + + vec3 normal = normalize(ellipsoidNormalCameraSpace); +#if USE_ACCURATE_NORMALS + normal = getTileNormal(fs_uv, levelWeights, + normalize(ellipsoidNormalCameraSpace), + normalize(ellipsoidTangentThetaCameraSpace), + normalize(ellipsoidTangentPhiCameraSpace)); +#endif /// USE_ACCURATE_NORMALS #if USE_COLORTEXTURE - - color = calculateColor( - color, - fs_uv, - levelWeights, - ColorLayers); + color = calculateColor( + color, + fs_uv, + levelWeights, + ColorLayers); #endif // USE_COLORTEXTURE #if USE_WATERMASK - color = calculateWater( - color, - fs_uv, - levelWeights, - WaterMasks, - normalize(ellipsoidNormalCameraSpace), - lightDirectionCameraSpace, // Should already be normalized - positionCameraSpace); + color = calculateWater( + color, + fs_uv, + levelWeights, + WaterMasks, + normal, + lightDirectionCameraSpace, // Should already be normalized + positionCameraSpace); #endif // USE_WATERMASK #if USE_NIGHTTEXTURE - color = calculateNight( - color, - fs_uv, - levelWeights, - NightLayers, - normalize(ellipsoidNormalCameraSpace), - lightDirectionCameraSpace); // Should already be normalized + color = calculateNight( + color, + fs_uv, + levelWeights, + NightLayers, + normalize(ellipsoidNormalCameraSpace), + lightDirectionCameraSpace); // Should already be normalized #endif // USE_NIGHTTEXTURE #if PERFORM_SHADING - color = calculateShadedColor( - color, - normalize(ellipsoidNormalCameraSpace), - lightDirectionCameraSpace); + color = calculateShadedColor( + color, + normal, + lightDirectionCameraSpace, + normalize(positionCameraSpace), + orenNayarRoughness); #endif // PERFORM_SHADING #if USE_ATMOSPHERE - // Temporary until the real atmosphere code is here - //color = color + vec4(0.5,0.5,1,0) * 0.3; // Just to see something for now - vec3 n = normalize(ellipsoidNormalCameraSpace); - vec3 l = lightDirectionCameraSpace; - vec3 c = normalize(positionCameraSpace); - float cosFactor = 1 - clamp(dot(-n * 0.9, c), 0, 1); - cosFactor *= 1.1; - cosFactor -= 0.1; - cosFactor = clamp(cosFactor, 0, 1); - cosFactor = cosFactor + pow(cosFactor, 5); - - float shadowLight = 0.15; - float cosFactorLight = pow(max(dot(-l, n), -shadowLight) + shadowLight, 0.8); - //float cosFactorScatter = pow(max(dot(l, n) + shadowLight, 0), 5); - //float cosFactorLight = max(dot(-lightDirectionCameraSpace, normalize(ellipsoidNormalCameraSpace)), 0); - //vec3 r = reflect(l, n); - //float scatteredLight = pow(clamp(dot(-r,c), 0, 1), 20); - vec3 atmosphereColor = vec3(0.5,0.5,1) * 2; - color = color + vec4(atmosphereColor,0) * cosFactor * cosFactorLight * 0.5; + // Temporary until the real atmosphere code is here + //color = color + vec4(0.5,0.5,1,0) * 0.3; // Just to see something for now + vec3 n = normalize(ellipsoidNormalCameraSpace); + vec3 l = lightDirectionCameraSpace; + vec3 c = normalize(positionCameraSpace); + float cosFactor = 1 - clamp(dot(-n * 0.9, c), 0, 1); + cosFactor *= 1.1; + cosFactor -= 0.1; + cosFactor = clamp(cosFactor, 0, 1); + cosFactor = cosFactor + pow(cosFactor, 5); + + float shadowLight = 0.15; + float cosFactorLight = pow(max(dot(-l, n), -shadowLight) + shadowLight, 0.8); + //float cosFactorScatter = pow(max(dot(l, n) + shadowLight, 0), 5); + //float cosFactorLight = max(dot(-lightDirectionCameraSpace, normalize(ellipsoidNormalCameraSpace)), 0); + //vec3 r = reflect(l, n); + //float scatteredLight = pow(clamp(dot(-r,c), 0, 1), 20); + vec3 atmosphereColor = vec3(0.5,0.5,1) * 2; + color = color + vec4(atmosphereColor,0) * cosFactor * cosFactorLight * 0.5; #endif // USE_ATMOSPHERE #if USE_OVERLAY - color = calculateOverlay( - color, - fs_uv, - levelWeights, - Overlays); + color = calculateOverlay( + color, + fs_uv, + levelWeights, + Overlays); #endif // USE_OVERLAY - - #if SHOW_HEIGHT_INTENSITIES - color.r *= 0.1; - color.g *= 0.1; - color.b *= 0.1; + color.r *= 0.1; + color.g *= 0.1; + color.b *= 0.1; - float untransformedHeight = getUntransformedTileVertexHeight(fs_uv, levelWeights); - float contourLine = fract(10*untransformedHeight) > 0.98 ? 1 : 0; - color.r += untransformedHeight; - color.b = contourLine; + float untransformedHeight = getUntransformedTileVertexHeight(fs_uv, levelWeights); + float contourLine = fract(10*untransformedHeight) > 0.98 ? 1 : 0; + color.r += untransformedHeight; + color.b = contourLine; #endif - #if SHOW_HEIGHT_RESOLUTION - color += 0.0001*calculateDebugColor(fs_uv, fs_position, vertexResolution); - #if USE_HEIGHTMAP - color.r = min(color.r, 0.8); - color.r += tileResolution(fs_uv, HeightLayers[0].pile.chunkTile0) > 0.9 ? 1 : 0; - #endif + color += 0.0001*calculateDebugColor(fs_uv, fs_position, vertexResolution); + #if USE_HEIGHTMAP + color.r = min(color.r, 0.8); + color.r += tileResolution(fs_uv, HeightLayers[0].pile.chunkTile0) > 0.9 ? 1 : 0; + #endif #endif - return color; + return color; } diff --git a/modules/globebrowsing/shaders/tileheight.hglsl b/modules/globebrowsing/shaders/tileheight.hglsl new file mode 100644 index 0000000000..2f8b6ea746 --- /dev/null +++ b/modules/globebrowsing/shaders/tileheight.hglsl @@ -0,0 +1,125 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef TILE_HEIGHT_HGLSL +#define TILE_HEIGHT_HGLSL + +#include "PowerScaling/powerScaling_vs.hglsl" + +#include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> +#include <${MODULE_GLOBEBROWSING}/shaders/ellipsoid.hglsl> + + +#ifndef USE_HEIGHTMAP +#define USE_HEIGHTMAP #{useAccurateNormals} +#endif //USE_HEIGHTMAP + +#ifndef USE_ACCURATE_NORMALS +#define USE_ACCURATE_NORMALS #{useAccurateNormals} +#endif //USE_ACCURATE_NORMALS + +#if USE_HEIGHTMAP +uniform Layer HeightLayers[NUMLAYERS_HEIGHTMAP]; +uniform float heightScale; +#endif // USE_HEIGHTMAP + +#if USE_ACCURATE_NORMALS +uniform float deltaTheta0; +uniform float deltaTheta1; +uniform float deltaPhi0; +uniform float deltaPhi1; +uniform float tileDelta; +#endif //USE_ACCURATE_NORMALS + +float getUntransformedTileHeight(vec2 uv, LevelWeights levelWeights){ + float height = CHUNK_DEFAULT_HEIGHT; + +#if USE_HEIGHTMAP + // Calculate desired level based on distance to the vertex on the ellipsoid + // Before any heightmapping is done + height = calculateUntransformedHeight( + uv, + levelWeights, // Variable to determine which texture to sample from + HeightLayers); // Three textures to sample from + +#endif // USE_HEIGHTMAP + + return height; +} + +float getTileHeight(vec2 uv, LevelWeights levelWeights){ + float height = CHUNK_DEFAULT_HEIGHT; + +#if USE_HEIGHTMAP + // Calculate desired level based on distance to the vertex on the ellipsoid + // Before any heightmapping is done + height = calculateHeight( + uv, + levelWeights, // Variable to determine which texture to sample from + HeightLayers); // Three textures to sample from +#endif // USE_HEIGHTMAP + + return height; +} + +float getTileHeightScaled(vec2 uv, LevelWeights levelWeights){ + float height = getTileHeight(uv, levelWeights); + +#if USE_HEIGHTMAP + height *= heightScale; +#endif // USE_HEIGHTMAP + + return height; +} + +vec3 getTileNormal( + vec2 uv, + LevelWeights levelWeights, + vec3 ellipsoidNormalCameraSpace, + vec3 ellipsoidTangentThetaCameraSpace, + vec3 ellipsoidTangentPhiCameraSpace) +{ + vec3 normal = ellipsoidNormalCameraSpace; + +#if USE_ACCURATE_NORMALS + float deltaPhi = mix(deltaPhi0, deltaPhi1, uv.x); + float deltaTheta = mix(deltaTheta0, deltaTheta1, uv.y); + + vec3 deltaPhiVec = ellipsoidTangentPhiCameraSpace * deltaPhi; + vec3 deltaThetaVec = ellipsoidTangentThetaCameraSpace * deltaTheta; + + float height00 = getTileHeightScaled(uv, levelWeights); + float height10 = getTileHeightScaled(uv + vec2(tileDelta, 0.0f), levelWeights); + float height01 = getTileHeightScaled(uv + vec2(0.0f, tileDelta), levelWeights); + + vec3 diffTheta = deltaThetaVec + ellipsoidNormalCameraSpace * (height10 - height00); + vec3 diffPhi = deltaPhiVec + ellipsoidNormalCameraSpace * (height01 - height00); + + normal = normalize(cross(diffTheta, diffPhi)); +#endif // USE_ACCURATE_NORMALS + return normal; +} + + +#endif // TILE_HEIGHT_HGLSL diff --git a/modules/globebrowsing/shaders/tilevertexheight.hglsl b/modules/globebrowsing/shaders/tilevertexheight.hglsl deleted file mode 100644 index 6733b30c96..0000000000 --- a/modules/globebrowsing/shaders/tilevertexheight.hglsl +++ /dev/null @@ -1,126 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef TILE_VERTEX_HEIGHT_HGLSL -#define TILE_VERTEX_HEIGHT_HGLSL - -#include "PowerScaling/powerScaling_vs.hglsl" - -#include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> - - -#if USE_HEIGHTMAP -uniform Layer HeightLayers[NUMLAYERS_HEIGHTMAP]; -#endif // USE_HEIGHTMAP - -uniform int xSegments; -uniform float skirtLength; - -uniform float distanceScaleFactor; -uniform int chunkLevel; - - -float getUntransformedTileVertexHeight(vec2 uv, LevelWeights levelWeights){ - float height = CHUNK_DEFAULT_HEIGHT; - -#if USE_HEIGHTMAP - // Calculate desired level based on distance to the vertex on the ellipsoid - // Before any heightmapping is done - height = calculateUntransformedHeight( - uv, - levelWeights, // Variable to determine which texture to sample from - HeightLayers); // Three textures to sample from - -#endif // USE_HEIGHTMAP - - return height; -} - - -float getTileVertexHeight(vec2 uv, LevelWeights levelWeights){ - float height = CHUNK_DEFAULT_HEIGHT; - -#if USE_HEIGHTMAP - // Calculate desired level based on distance to the vertex on the ellipsoid - // Before any heightmapping is done - height = calculateHeight( - uv, - levelWeights, // Variable to determine which texture to sample from - HeightLayers); // Three textures to sample from - -#endif // USE_HEIGHTMAP - - return height; -} - -// This function is currently not correct -vec3 getTileVertexNormal( - vec2 uv, - LevelWeights levelWeights, - vec3 ellipsoidNormal) { - vec3 normal = ellipsoidNormal; - -#if USE_HEIGHTMAP - float sampleDelta = 1.0 / xSegments; - - float heightCenter = calculateHeight( - uv, - levelWeights, - HeightLayers); - float heightOffsetX = calculateHeight( - uv + vec2(sampleDelta, 0.0), - levelWeights, - HeightLayers); - float heightOffsetY = calculateHeight( - uv + vec2(0.0, sampleDelta), - levelWeights, - HeightLayers); - - vec3 e0 = normalize(cross(vec3(0,0,1), ellipsoidNormal)); - vec3 e1 = cross(ellipsoidNormal, e0); - vec3 e2 = ellipsoidNormal; - - vec3 v0 = e0 * sampleDelta * 3000000 + e2 * heightOffsetX; - vec3 v1 = e1 * sampleDelta * 3000000 + e2 * heightOffsetY; - - vec3 n = cross(v0, v1); - - normal = normalize(n); - -#endif // USE_HEIGHTMAP - return normal; -} - -bool tileVertexIsSkirtVertex(){ - int vertexIDx = gl_VertexID % (xSegments + 3); - int vertexIDy = gl_VertexID / (xSegments + 3); - return vertexIDx == 0 || vertexIDy == 0 || - vertexIDx == (xSegments + 2) || vertexIDy == (xSegments + 2); -} - -float getTileVertexSkirtLength(){ - return tileVertexIsSkirtVertex() ? skirtLength : 0.0; -} - -#endif // TILE_VERTEX_HEIGHT_HGLSL diff --git a/modules/globebrowsing/shaders/tilevertexskirt.hglsl b/modules/globebrowsing/shaders/tilevertexskirt.hglsl new file mode 100644 index 0000000000..1c86a24986 --- /dev/null +++ b/modules/globebrowsing/shaders/tilevertexskirt.hglsl @@ -0,0 +1,44 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef TILE_VERTEX_SKIRT_HGLSL +#define TILE_VERTEX_SKIRT_HGLSL + +#include "PowerScaling/powerScaling_vs.hglsl" + +uniform int xSegments; +uniform float skirtLength; + +bool tileVertexIsSkirtVertex(){ + int vertexIDx = gl_VertexID % (xSegments + 3); + int vertexIDy = gl_VertexID / (xSegments + 3); + return vertexIDx == 0 || vertexIDy == 0 || + vertexIDx == (xSegments + 2) || vertexIDy == (xSegments + 2); +} + +float getTileVertexSkirtLength(){ + return tileVertexIsSkirtVertex() ? skirtLength : 0.0; +} + +#endif // TILE_VERTEX_SKIRT_HGLSL diff --git a/openspace.cfg b/openspace.cfg index b44bf346cb..5d12c0b6eb 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -24,7 +24,6 @@ return { -- Streaming OpenSpace via Spout to OBS -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"}, - --SGCTConfig = "${CONFIG}/openvr_oculusRiftCv1.xml", --SGCTConfig = "${CONFIG}/openvr_htcVive.xml", From 2e4f31ded88b99950dd5ce067082d6da604591ed Mon Sep 17 00:00:00 2001 From: Kalle Bladin Date: Fri, 14 Jul 2017 17:17:17 +0200 Subject: [PATCH 190/192] Interaction Updates (#353) * Interaction speed is not dependent on framerate * Split up interaction code in files and perform smooth interpolation when changing focus * Abstract interaction code in to functions. * Interpolation time is dependent on angle to focus node. * Use correct delta time when interpolating * Fix bug regarding decomposition of camera rotation. * Make orbital interaction mode behave as globe browsing and no longer use interactiondepth below ellipsoid. * Do not always rotate with object. Depending on distance * Remove interaction depth below ellipsoid. Now able to interact without renderable * Remove specification of interactionDepthBelowEllipsoid and cameraMinHeight * Remove GlobeBrowsingInteractionMode * Rename OrbitalInteractionMode to OrbitalNavigator and no longer extend interactionmode. * Move properties from interaction handler to orbital navigator * Use smooth step for follow rotation interpolator * Rename KeyframeInteractionMode to KeyframeNavigator * Rename files * Clean up. * Separate mousestate from orbitalnavigator * Clean up * Split keybindingmanager from interactionhandler interactionhandler * Rename interactionhandler to navigationhandler * Rename files * Clean up * Take back usage of gotochunk and gotogeo * Rename lua library navigation * Move functionality from navigationhandler to keyframenavigator * Update scripts for navigation * Comment code * Clean up * Solve but that caused NaN values for camera position when being in center of globe and setting focus to the globe. * Update jenkins file to remove build folder before building. * Fix error in jenkins script * Update jenkins file * Update jenkins file * Revert jenkins file * I hope this makes Jenkins happy. * Line endings God damnit * Line endings * Clean up * Fix compilation issue * Take back default scene. * Fix indentation * Move functions goToGeo and goToChunk to GlobeBrowsingModule. * Include algorithm for std::find * Remove auto and other clean up --- data/scene/globebrowsing.scene | 4 +- data/scene/lodglobes/earth/earth.mod | 2 - .../lodglobes/jupiter/callisto/callisto.mod | 2 - .../scene/lodglobes/jupiter/europa/europa.mod | 2 - .../lodglobes/jupiter/ganymede/ganymede.mod | 2 - data/scene/lodglobes/jupiter/io/io.mod | 2 - .../lodglobes/jupiter/jupiter/jupiter.mod | 2 - data/scene/lodglobes/mars/mars.mod | 4 - data/scene/lodglobes/moon/moon.mod | 3 - data/scene/lodglobes/neptune/neptune.mod | 2 - data/scene/lodglobes/saturn/saturn.mod | 2 - data/scene/lodglobes/uranus/uranus.mod | 2 - data/scene/lodglobes/venus/venus.mod | 2 - include/openspace/engine/openspaceengine.h | 11 +- include/openspace/interaction/controller.h | 6 +- .../openspace/interaction/delayedvariable.h | 59 ++ .../openspace/interaction/delayedvariable.inl | 76 ++ include/openspace/interaction/inputstate.h | 70 ++ .../openspace/interaction/interactionmode.h | 286 ------- include/openspace/interaction/interpolator.h | 65 ++ .../openspace/interaction/interpolator.inl | 85 ++ .../openspace/interaction/keybindingmanager.h | 87 ++ .../openspace/interaction/keyframenavigator.h | 69 ++ include/openspace/interaction/mousestate.h | 80 ++ ...teractionhandler.h => navigationhandler.h} | 102 +-- .../openspace/interaction/orbitalnavigator.h | 197 +++++ include/openspace/rendering/renderable.h | 3 + include/openspace/scene/scenegraphnode.h | 3 + include/openspace/util/updatestructures.h | 15 + modules/globebrowsing/chunk/chunk.cpp | 2 +- .../globebrowsing/geometry/geodeticpatch.h | 3 +- modules/globebrowsing/globebrowsingmodule.cpp | 178 +++- modules/globebrowsing/globebrowsingmodule.h | 24 +- .../globebrowsing/globebrowsingmodule_lua.inl | 42 + .../globebrowsing/globes/chunkedlodglobe.cpp | 2 +- .../globebrowsing/globes/renderableglobe.cpp | 40 +- .../globebrowsing/globes/renderableglobe.h | 7 +- .../globebrowsing/rendering/chunkrenderer.cpp | 4 +- .../rendering/gpu/gpulayergroup.cpp | 2 +- modules/onscreengui/onscreenguimodule.cpp | 4 +- .../onscreengui/src/guiorigincomponent.cpp | 6 +- .../onscreengui/src/guiparallelcomponent.cpp | 4 +- modules/touch/include/TouchInteraction.h | 4 +- modules/touch/src/TouchInteraction.cpp | 8 +- modules/touch/src/TuioEar.cpp | 4 +- modules/touch/touchmodule.cpp | 6 +- scripts/common.lua | 6 +- src/CMakeLists.txt | 23 +- src/documentation/core_registration.cpp | 6 +- src/engine/openspaceengine.cpp | 55 +- src/interaction/controller.cpp | 4 +- src/interaction/inputstate.cpp | 97 +++ src/interaction/interactionhandler.cpp | 563 ------------ src/interaction/interactionmode.cpp | 800 ------------------ src/interaction/keybindingmanager.cpp | 178 ++++ ...dler_lua.inl => keybindingmanager_lua.inl} | 117 +-- src/interaction/keyframenavigator.cpp | 127 +++ src/interaction/mousestate.cpp | 177 ++++ src/interaction/navigationhandler.cpp | 299 +++++++ src/interaction/navigationhandler_lua.inl | 113 +++ src/interaction/orbitalnavigator.cpp | 532 ++++++++++++ src/network/parallelconnection.cpp | 26 +- src/query/query.cpp | 2 +- src/rendering/renderable.cpp | 11 + src/rendering/renderengine.cpp | 2 +- src/scene/scene.cpp | 2 +- src/scene/scenegraphnode.cpp | 15 + src/util/camera.cpp | 1 - 68 files changed, 2764 insertions(+), 1977 deletions(-) create mode 100644 include/openspace/interaction/delayedvariable.h create mode 100644 include/openspace/interaction/delayedvariable.inl create mode 100644 include/openspace/interaction/inputstate.h delete mode 100644 include/openspace/interaction/interactionmode.h create mode 100644 include/openspace/interaction/interpolator.h create mode 100644 include/openspace/interaction/interpolator.inl create mode 100644 include/openspace/interaction/keybindingmanager.h create mode 100644 include/openspace/interaction/keyframenavigator.h create mode 100644 include/openspace/interaction/mousestate.h rename include/openspace/interaction/{interactionhandler.h => navigationhandler.h} (59%) create mode 100644 include/openspace/interaction/orbitalnavigator.h create mode 100644 src/interaction/inputstate.cpp delete mode 100644 src/interaction/interactionhandler.cpp delete mode 100644 src/interaction/interactionmode.cpp create mode 100644 src/interaction/keybindingmanager.cpp rename src/interaction/{interactionhandler_lua.inl => keybindingmanager_lua.inl} (61%) create mode 100644 src/interaction/keyframenavigator.cpp create mode 100644 src/interaction/mousestate.cpp create mode 100644 src/interaction/navigationhandler.cpp create mode 100644 src/interaction/navigationhandler_lua.inl create mode 100644 src/interaction/orbitalnavigator.cpp diff --git a/data/scene/globebrowsing.scene b/data/scene/globebrowsing.scene index 9e6243d135..0c2b8d23c3 100644 --- a/data/scene/globebrowsing.scene +++ b/data/scene/globebrowsing.scene @@ -78,7 +78,7 @@ function postInitialization() openspace.setPropertyValue("Earth.RenderableGlobe.Debug.levelByProjectedAreaElseDistance", false) openspace.setPropertyValue("Earth.RenderableGlobe.Layers.ColorLayers.blendTileLevels", true) - openspace.resetCameraDirection() + openspace.globebrowsing.goToGeo(0, 0, 20000000) openspace.printInfo("Done setting default values") end @@ -89,7 +89,7 @@ return { CommonFolder = "common", Camera = { Focus = "Earth", - Position = {30000000, 0, 0}, + Position = {0, 0, 0}, Rotation = {0.758797, 0.221490, -0.605693, -0.091135}, }, diff --git a/data/scene/lodglobes/earth/earth.mod b/data/scene/lodglobes/earth/earth.mod index b55e23430f..0819aa8638 100644 --- a/data/scene/lodglobes/earth/earth.mod +++ b/data/scene/lodglobes/earth/earth.mod @@ -63,8 +63,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = earthEllipsoid, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/jupiter/callisto/callisto.mod b/data/scene/lodglobes/jupiter/callisto/callisto.mod index 53b8cee865..302fc7a103 100644 --- a/data/scene/lodglobes/jupiter/callisto/callisto.mod +++ b/data/scene/lodglobes/jupiter/callisto/callisto.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {2631000, 2631000, 2631000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/jupiter/europa/europa.mod b/data/scene/lodglobes/jupiter/europa/europa.mod index 720e68d7db..d84d20d48d 100644 --- a/data/scene/lodglobes/jupiter/europa/europa.mod +++ b/data/scene/lodglobes/jupiter/europa/europa.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {1561000, 1561000, 1561000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod index 098014cc0c..e37a193bb8 100644 --- a/data/scene/lodglobes/jupiter/ganymede/ganymede.mod +++ b/data/scene/lodglobes/jupiter/ganymede/ganymede.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {2631000, 2631000, 2631000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/jupiter/io/io.mod b/data/scene/lodglobes/jupiter/io/io.mod index dc6b7c2b8e..87dfc06b20 100644 --- a/data/scene/lodglobes/jupiter/io/io.mod +++ b/data/scene/lodglobes/jupiter/io/io.mod @@ -23,8 +23,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {1821300, 1821300, 1821300}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/jupiter/jupiter/jupiter.mod b/data/scene/lodglobes/jupiter/jupiter/jupiter.mod index 2c6610b3ae..58dc65149d 100644 --- a/data/scene/lodglobes/jupiter/jupiter/jupiter.mod +++ b/data/scene/lodglobes/jupiter/jupiter/jupiter.mod @@ -34,8 +34,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {71492000, 71492000, 66854000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/mars/mars.mod b/data/scene/lodglobes/mars/mars.mod index 7443aa8f2f..ceee56e4ea 100644 --- a/data/scene/lodglobes/mars/mars.mod +++ b/data/scene/lodglobes/mars/mars.mod @@ -32,11 +32,7 @@ return { Renderable = { Type = "RenderableGlobe", Radii = marsEllipsoid, - CameraMinHeight = 10, SegmentsPerPatch = 90, - -- Allows camera to go down 10000 meters below the reference ellipsoid - -- Useful when having negative height map values - InteractionDepthBelowEllipsoid = 10000, Layers = { ColorLayers = { { diff --git a/data/scene/lodglobes/moon/moon.mod b/data/scene/lodglobes/moon/moon.mod index 40499d6004..1ddb3cf044 100644 --- a/data/scene/lodglobes/moon/moon.mod +++ b/data/scene/lodglobes/moon/moon.mod @@ -19,10 +19,7 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {1738140, 1738140, 1735970}, -- Moons's radius - CameraMinHeight = 300, SegmentsPerPatch = 64, - -- Allows camera to go down 10000 meters below the reference ellipsoid - InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values Layers = { ColorLayers = { { diff --git a/data/scene/lodglobes/neptune/neptune.mod b/data/scene/lodglobes/neptune/neptune.mod index 31bac3a1fe..99513e18bb 100644 --- a/data/scene/lodglobes/neptune/neptune.mod +++ b/data/scene/lodglobes/neptune/neptune.mod @@ -31,8 +31,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {24764000, 24764000, 24314000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/saturn/saturn.mod b/data/scene/lodglobes/saturn/saturn.mod index cb04b02d13..dc1ef691eb 100644 --- a/data/scene/lodglobes/saturn/saturn.mod +++ b/data/scene/lodglobes/saturn/saturn.mod @@ -31,8 +31,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {60268000, 60268000, 54364000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/uranus/uranus.mod b/data/scene/lodglobes/uranus/uranus.mod index 81dd7f8eb3..b8cda62a16 100644 --- a/data/scene/lodglobes/uranus/uranus.mod +++ b/data/scene/lodglobes/uranus/uranus.mod @@ -31,8 +31,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {25559000, 25559000, 24973000}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/data/scene/lodglobes/venus/venus.mod b/data/scene/lodglobes/venus/venus.mod index 6288883665..285f88f466 100644 --- a/data/scene/lodglobes/venus/venus.mod +++ b/data/scene/lodglobes/venus/venus.mod @@ -36,8 +36,6 @@ return { Renderable = { Type = "RenderableGlobe", Radii = {6051900, 6051900, 6051800}, - CameraMinHeight = 300, - InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values SegmentsPerPatch = 64, Layers = { ColorLayers = { diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 00de495380..df4c372ee5 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -62,7 +62,10 @@ class SyncEngine; class TimeManager; class WindowWrapper; -namespace interaction { class InteractionHandler; } +namespace interaction { + class NavigationHandler; + class KeyBindingManager; +} namespace gui { class GUI; } namespace properties { class PropertyOwner; } namespace scripting { @@ -123,7 +126,8 @@ public: TimeManager& timeManager(); WindowWrapper& windowWrapper(); ghoul::fontrendering::FontManager& fontManager(); - interaction::InteractionHandler& interactionHandler(); + interaction::NavigationHandler& navigationHandler(); + interaction::KeyBindingManager& keyBindingManager(); properties::PropertyOwner& globalPropertyOwner(); scripting::ScriptEngine& scriptEngine(); scripting::ScriptScheduler& scriptScheduler(); @@ -197,7 +201,8 @@ private: std::unique_ptr _windowWrapper; std::unique_ptr _commandlineParser; std::unique_ptr _fontManager; - std::unique_ptr _interactionHandler; + std::unique_ptr _navigationHandler; + std::unique_ptr _keyBindingManager; std::unique_ptr _scriptEngine; std::unique_ptr _scriptScheduler; std::unique_ptr _virtualPropertyManager; diff --git a/include/openspace/interaction/controller.h b/include/openspace/interaction/controller.h index 4e262a0287..baa63c12a3 100644 --- a/include/openspace/interaction/controller.h +++ b/include/openspace/interaction/controller.h @@ -33,7 +33,7 @@ namespace openspace { namespace interaction { -class InteractionHandler; +class NavigationHandler; class Controller { public: @@ -41,10 +41,10 @@ public: _handler(nullptr) {} - void setHandler(InteractionHandler* handler); + void setHandler(NavigationHandler* handler); protected: - InteractionHandler* _handler; + NavigationHandler* _handler; }; } // namespace interaction diff --git a/include/openspace/interaction/delayedvariable.h b/include/openspace/interaction/delayedvariable.h new file mode 100644 index 0000000000..ad8b7e039e --- /dev/null +++ b/include/openspace/interaction/delayedvariable.h @@ -0,0 +1,59 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___DELAYEDVARIABLE___H__ +#define __OPENSPACE_CORE___DELAYEDVARIABLE___H__ + +namespace openspace { +namespace interaction { + +/** + * Class that acts as a smoothing filter to a variable. The filter has a step + * response on a form that resembles the function y = 1-e^(-t/scale). The variable + * will be updated as soon as it is set to a value (calling the set() function). +*/ +template +class DelayedVariable { +public: + DelayedVariable(ScaleType scaleFactor, ScaleType friction); + void set(T value, double dt); + void decelerate(double dt); + void setHard(T value); + void setFriction(ScaleType friction); + void setScaleFactor(ScaleType scaleFactor); + T get() const; + +private: + ScaleType _scaleFactor; + ScaleType _friction; + T _targetValue; + T _currentValue; +}; + +} // namespace interaction +} // namespace openspace + +#include "delayedvariable.inl" + +#endif // __OPENSPACE_CORE___DELAYEDVARIABLE___H__ diff --git a/include/openspace/interaction/delayedvariable.inl b/include/openspace/interaction/delayedvariable.inl new file mode 100644 index 0000000000..03e8137f13 --- /dev/null +++ b/include/openspace/interaction/delayedvariable.inl @@ -0,0 +1,76 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include +#include + +namespace openspace { +namespace interaction { + +template +DelayedVariable::DelayedVariable(ScaleType scaleFactor, ScaleType friction) + : _scaleFactor(std::move(scaleFactor)) + , _friction(friction) +{ + ghoul_assert(_friction >= ScaleType(0.0), "Friction must be positive"); +} + +template +void DelayedVariable::set(T value, double dt) { + _targetValue = value; + _currentValue = _currentValue + (_targetValue - _currentValue) * + glm::min(_scaleFactor * dt, 1.0); // less or equal to 1.0 keeps it stable +} + +template +void DelayedVariable::decelerate(double dt) { + _currentValue = _currentValue + (- _currentValue) * + glm::min(_scaleFactor * _friction * dt, 1.0); + // less or equal to 1.0 keeps it stable +} + +template +void DelayedVariable::setHard(T value) { + _targetValue = value; + _currentValue = value; +} + +template +void DelayedVariable::setFriction(ScaleType friction) { + _friction = friction; + ghoul_assert(_friction >= ScaleType(0.0), "Friction must be positive"); +} + +template +void DelayedVariable::setScaleFactor(ScaleType scaleFactor) { + _scaleFactor = scaleFactor; +} + +template +T DelayedVariable::get() const { + return _currentValue; +} + +} // namespace interaction +} // namespace openspace diff --git a/include/openspace/interaction/inputstate.h b/include/openspace/interaction/inputstate.h new file mode 100644 index 0000000000..250a51743a --- /dev/null +++ b/include/openspace/interaction/inputstate.h @@ -0,0 +1,70 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___INPUTSTATE___H__ +#define __OPENSPACE_CORE___INPUTSTATE___H__ + +#include +#include + +#include + +#include + +namespace openspace { +namespace interaction { + +class InputState { +public: + InputState() = default; + ~InputState() = default; + + // Callback functions + void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); + void mouseButtonCallback(MouseButton button, MouseAction action); + void mousePositionCallback(double mouseX, double mouseY); + void mouseScrollWheelCallback(double mouseScrollDelta); + + // Accessors + const std::list>& getPressedKeys() const; + const std::list& getPressedMouseButtons() const; + glm::dvec2 getMousePosition() const; + double getMouseScrollDelta() const; + + bool isKeyPressed(std::pair keyModPair) const; + bool isKeyPressed(Key key) const; + bool isMouseButtonPressed(MouseButton mouseButton) const; + +private: + // Input from keyboard and mouse + std::list> _keysDown; + std::list _mouseButtonsDown; + glm::dvec2 _mousePosition; + double _mouseScrollDelta; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___INPUTSTATE___H__ diff --git a/include/openspace/interaction/interactionmode.h b/include/openspace/interaction/interactionmode.h deleted file mode 100644 index dc99ec1498..0000000000 --- a/include/openspace/interaction/interactionmode.h +++ /dev/null @@ -1,286 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#ifndef __OPENSPACE_CORE___INTERACTIONMODE___H__ -#define __OPENSPACE_CORE___INTERACTIONMODE___H__ - -#include -#include -#include -#include - -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -#include -#include -#include -#endif - -#include - -namespace openspace { - -class Camera; -class SceneGraphNode; - -namespace globebrowsing { - class RenderableGlobe; -} - -namespace interaction { - - template - class Interpolator - { - public: - Interpolator(std::function transferFunction) - : _t(0.0) - , _transferFunction(transferFunction) {}; - ~Interpolator() {}; - - void start() { _t = 0.0; }; - void end() { _t = 1.0; }; - void step(double delta) { _t += delta; }; - - T value() { return _transferFunction(_t); }; - bool isInterpolating() { return _t < 1.0; }; - private: - std::function _transferFunction; - double _t; - }; - - class InputState - { - public: - InputState(); - ~InputState(); - - // Callback functions - void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); - void mouseButtonCallback(MouseButton button, MouseAction action); - void mousePositionCallback(double mouseX, double mouseY); - void mouseScrollWheelCallback(double mouseScrollDelta); - - // Accessors - const std::list >& getPressedKeys() const; - const std::list& getPressedMouseButtons() const; - glm::dvec2 getMousePosition() const; - double getMouseScrollDelta() const; - const std::vector& keyframes() const; - - bool isKeyPressed(std::pair keyModPair) const; - bool isKeyPressed(Key key) const; - bool isMouseButtonPressed(MouseButton mouseButton) const; - private: - // Input from keyboard and mouse - std::list > _keysDown; - std::list _mouseButtonsDown; - glm::dvec2 _mousePosition; - double _mouseScrollDelta; - }; - - - -class InteractionMode { -public: - InteractionMode(); - virtual ~InteractionMode(); - - // Mutators - virtual void setFocusNode(SceneGraphNode* focusNode); - - // Accessors - SceneGraphNode* focusNode(); - Interpolator& rotateToFocusNodeInterpolator(); - virtual bool followingNodeRotation() const = 0; - - virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime) = 0; - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime) = 0; - -protected: - /** - Inner class that acts as a smoothing filter to a variable. The filter has a step - response on a form that resembles the function y = 1-e^(-t/scale). The variable - will be updates as soon as it is set to a value (calling the set() function). - */ - template - class DelayedVariable { - public: - DelayedVariable(ScaleType scaleFactor, ScaleType friction) { - _scaleFactor = scaleFactor; - _friction = glm::max(friction, ScaleType(0.0)); - } - void set(T value, double dt) { - _targetValue = value; - _currentValue = _currentValue + (_targetValue - _currentValue) * - std::min(_scaleFactor * dt, 1.0); // less or equal to 1.0 keeps it stable - } - void decelerate(double dt) { - _currentValue = _currentValue + (- _currentValue) * - std::min(_scaleFactor * _friction * dt, 1.0); // less or equal to 1.0 keeps it stable - } - void setHard(T value) { - _targetValue = value; - _currentValue = value; - } - void setFriction(ScaleType friction) { - _friction = glm::max(friction, ScaleType(0.0)); - } - void setScaleFactor(ScaleType scaleFactor) { - _scaleFactor = scaleFactor; - } - T get() { - return _currentValue; - } - private: - ScaleType _scaleFactor; - ScaleType _friction; - T _targetValue; - T _currentValue; - }; - - struct MouseState { - MouseState(double scaleFactor) - : velocity(scaleFactor, 1) - , previousPosition(0.0, 0.0) {} - void setFriction(double friction) { - velocity.setFriction(friction); - } - void setVelocityScaleFactor(double scaleFactor) { - velocity.setScaleFactor(scaleFactor); - } - glm::dvec2 previousPosition; - DelayedVariable velocity; - }; - - SceneGraphNode* _focusNode = nullptr; - glm::dvec3 _previousFocusNodePosition; - glm::dquat _previousFocusNodeRotation; - - - Interpolator _rotateToFocusNodeInterpolator; -}; - -class KeyframeInteractionMode : public InteractionMode -{ -public: - struct CameraPose { - glm::dvec3 position; - glm::quat rotation; - std::string focusNode; - bool followFocusNodeRotation; - }; - - KeyframeInteractionMode(); - ~KeyframeInteractionMode(); - - virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - bool followingNodeRotation() const override; - Timeline& timeline(); - -private: - Timeline _cameraPoseTimeline; -}; - -class GlobeBrowsingInteractionMode; - -class OrbitalInteractionMode : public InteractionMode -{ -public: - class MouseStates - { - public: - /** - \param sensitivity - \param velocityScaleFactor can be set to 60 to remove the inertia of the - interaction. Lower value will make it harder to move the camera. - */ - MouseStates(double sensitivity, double velocityScaleFactor); - void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); - void setRotationalFriction(double friction); - void setHorizontalFriction(double friction); - void setVerticalFriction(double friction); - void setSensitivity(double sensitivity); - void setVelocityScaleFactor(double scaleFactor); - - glm::dvec2 synchedGlobalRotationMouseVelocity(); - glm::dvec2 synchedLocalRotationMouseVelocity(); - glm::dvec2 synchedTruckMovementMouseVelocity(); - glm::dvec2 synchedLocalRollMouseVelocity(); - glm::dvec2 synchedGlobalRollMouseVelocity(); - - private: - double _sensitivity; - - MouseState _globalRotationMouseState; - MouseState _localRotationMouseState; - MouseState _truckMovementMouseState; - MouseState _localRollMouseState; - MouseState _globalRollMouseState; - }; - - OrbitalInteractionMode(std::shared_ptr mouseStates); - ~OrbitalInteractionMode(); - - //virtual void update(Camera& camera, const InputState& inputState, double deltaTime); - - virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - bool followingNodeRotation() const override; - -protected: - //void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - std::shared_ptr _mouseStates; -}; - -class GlobeBrowsingInteractionMode : public OrbitalInteractionMode -{ -public: - GlobeBrowsingInteractionMode(std::shared_ptr mouseStates); - ~GlobeBrowsingInteractionMode(); - - virtual void setFocusNode(SceneGraphNode* focusNode); - //virtual void update(Camera& camera, const InputState& inputState, double deltaTime); - virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); - bool followingNodeRotation() const override; -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - void goToChunk(Camera& camera, globebrowsing::TileIndex ti, glm::vec2 uv, - bool resetCameraDirection); - void goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, - bool resetCameraDirection); - - void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3); - void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2); -#endif -private: - //void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - globebrowsing::RenderableGlobe* _globe; -#endif -}; - -} // namespace interaction -} // namespace openspace - -#endif // __OPENSPACE_CORE___INTERACTIONMODE___H__ diff --git a/include/openspace/interaction/interpolator.h b/include/openspace/interaction/interpolator.h new file mode 100644 index 0000000000..cf4bafb25d --- /dev/null +++ b/include/openspace/interaction/interpolator.h @@ -0,0 +1,65 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___INTERPOLATOR___H__ +#define __OPENSPACE_CORE___INTERPOLATOR___H__ + +#include + +namespace openspace { +namespace interaction { + +/* + * Interpolates a typename T using a transfer function. + */ +template +class Interpolator { +public: + Interpolator(); + ~Interpolator() = default; + + void start(); + void end(); + void setDeltaTime(float deltaTime); + void setTransferFunction(std::function transferFunction); + void setInterpolationTime(float interpolationTime); + void step(); + + float deltaTimeScaled() const; + T value() const; + bool isInterpolating() const; + +private: + std::function _transferFunction; + float _t; + float _interpolationTime; + float _scaledDeltaTime; +}; + +} // namespace interaction +} // namespace openspace + +#include "interpolator.inl" + +#endif // __OPENSPACE_CORE___INTERPOLATOR___H__ diff --git a/include/openspace/interaction/interpolator.inl b/include/openspace/interaction/interpolator.inl new file mode 100644 index 0000000000..c9ad0ed612 --- /dev/null +++ b/include/openspace/interaction/interpolator.inl @@ -0,0 +1,85 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +namespace openspace { +namespace interaction { + +template +Interpolator::Interpolator() +: _transferFunction([](float t){ return t; }) +, _t(0.0) +, _interpolationTime(1.0) {}; + +template +void Interpolator::start() { + _t = 0.0; +}; + +template +void Interpolator::end() { + _t = 1.0; +} + +template +void Interpolator::setDeltaTime(float deltaTime) { + _scaledDeltaTime = deltaTime / _interpolationTime; +} + +template +void Interpolator::setTransferFunction(std::function transferFunction) { + _transferFunction = transferFunction; +} + +template +void Interpolator::setInterpolationTime(float interpolationTime) { + _interpolationTime = interpolationTime; +} + +template +void Interpolator::step() { + _t += _scaledDeltaTime; + _t = glm::clamp(_t, 0.0f, 1.0f); +} + +template +float Interpolator::deltaTimeScaled() const { + return _scaledDeltaTime; +} + +template +T Interpolator::value() const { + return _transferFunction(_t); +} + +template +bool Interpolator::isInterpolating() const { + return _t < 1.0 && _t >= 0.0; +} + +} // namespace interaction +} // namespace openspace diff --git a/include/openspace/interaction/keybindingmanager.h b/include/openspace/interaction/keybindingmanager.h new file mode 100644 index 0000000000..2d4432f06f --- /dev/null +++ b/include/openspace/interaction/keybindingmanager.h @@ -0,0 +1,87 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___KEYBINDINGMANAGER___H__ +#define __OPENSPACE_CORE___KEYBINDINGMANAGER___H__ + +#include +#include +#include + +#include + +namespace openspace { + +class Camera; +class SceneGraphNode; + +namespace interaction { + +class KeyBindingManager : public DocumentationGenerator +{ +public: + KeyBindingManager(); + ~KeyBindingManager() = default; + + void resetKeyBindings(); + + void bindKeyLocal( + Key key, + KeyModifier modifier, + std::string luaCommand, + std::string documentation = "" + ); + + void bindKey( + Key key, + KeyModifier modifier, + std::string luaCommand, + std::string documentation = "" + ); + + static scripting::LuaLibrary luaLibrary(); + + // Callback functions + void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); + +private: + using Synchronized = ghoul::Boolean; + + struct KeyInformation { + std::string command; + Synchronized synchronization; + std::string documentation; + }; + + std::string generateJson() const override; + + bool _cameraUpdatedFromScript = false; + + std::multimap _keyLua; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___KEYBINDINGMANAGER___H__ diff --git a/include/openspace/interaction/keyframenavigator.h b/include/openspace/interaction/keyframenavigator.h new file mode 100644 index 0000000000..511e2ae3df --- /dev/null +++ b/include/openspace/interaction/keyframenavigator.h @@ -0,0 +1,69 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__ +#define __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__ + +#include +#include + +#include +#include + +namespace openspace { + +class Camera; + +namespace interaction { + +class KeyframeNavigator +{ +public: + struct CameraPose { + glm::dvec3 position; + glm::quat rotation; + std::string focusNode; + bool followFocusNodeRotation; + }; + + KeyframeNavigator() = default; + ~KeyframeNavigator() = default; + + void updateCamera(Camera& camera); + Timeline& timeline(); + + void addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose); + void removeKeyframesAfter(double timestamp); + void clearKeyframes(); + size_t nKeyframes() const; + const std::vector& keyframes() const; + +private: + Timeline _cameraPoseTimeline; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__ diff --git a/include/openspace/interaction/mousestate.h b/include/openspace/interaction/mousestate.h new file mode 100644 index 0000000000..c6db1380a7 --- /dev/null +++ b/include/openspace/interaction/mousestate.h @@ -0,0 +1,80 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___MOUSESTATE___H__ +#define __OPENSPACE_CORE___MOUSESTATE___H__ + +#include +#include + +#include + +namespace openspace { +namespace interaction { + +struct MouseState { + MouseState(double scaleFactor); + void setFriction(double friction); + void setVelocityScaleFactor(double scaleFactor); + + glm::dvec2 previousPosition; + DelayedVariable velocity; +}; + +class MouseStates +{ +public: + /** + \param sensitivity + \param velocityScaleFactor can be set to 60 to remove the inertia of the + interaction. Lower value will make it harder to move the camera. + */ + MouseStates(double sensitivity, double velocityScaleFactor); + void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); + void setRotationalFriction(double friction); + void setHorizontalFriction(double friction); + void setVerticalFriction(double friction); + void setSensitivity(double sensitivity); + void setVelocityScaleFactor(double scaleFactor); + + glm::dvec2 globalRotationMouseVelocity() const; + glm::dvec2 localRotationMouseVelocity() const; + glm::dvec2 truckMovementMouseVelocity() const; + glm::dvec2 localRollMouseVelocity() const; + glm::dvec2 globalRollMouseVelocity() const; + +private: + double _sensitivity; + + MouseState _globalRotationMouseState; + MouseState _localRotationMouseState; + MouseState _truckMovementMouseState; + MouseState _localRollMouseState; + MouseState _globalRollMouseState; +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___MOUSESTATE___H__ diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/navigationhandler.h similarity index 59% rename from include/openspace/interaction/interactionhandler.h rename to include/openspace/interaction/navigationhandler.h index 162404d227..2d0c930d4a 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/navigationhandler.h @@ -22,14 +22,13 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_CORE___INTERACTIONHANDLER___H__ -#define __OPENSPACE_CORE___INTERACTIONHANDLER___H__ +#ifndef __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ +#define __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ -#include #include -#include -#include +#include +#include #include #include #include @@ -38,10 +37,6 @@ #include -#include - -#include - namespace openspace { class Camera; @@ -49,11 +44,10 @@ class SceneGraphNode; namespace interaction { -class InteractionHandler : public properties::PropertyOwner, public DocumentationGenerator -{ +class NavigationHandler : public properties::PropertyOwner { public: - InteractionHandler(); - ~InteractionHandler(); + NavigationHandler(); + ~NavigationHandler(); void initialize(); void deinitialize(); @@ -63,39 +57,9 @@ public: void setCamera(Camera* camera); void resetCameraDirection(); - // Interaction mode setters - void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); - InteractionMode* interactionMode(); + void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); - void goToChunk(int x, int y, int level); - void goToGeo(double latitude, double longitude); - - void resetKeyBindings(); - - void addKeyframe(double timestamp, KeyframeInteractionMode::CameraPose pose); - void removeKeyframesAfter(double timestamp); - void clearKeyframes(); - size_t nKeyframes() const; - const std::vector& keyframes() const; - - void bindKeyLocal( - Key key, - KeyModifier modifier, - std::string luaCommand, - std::string documentation = "" - ); - void bindKey( - Key key, - KeyModifier modifier, - std::string luaCommand, - std::string documentation = "" - ); - void lockControls(); - void unlockControls(); - - //void update(double deltaTime); void updateCamera(double deltaTime); - void updateInputStates(double timeSinceLastUpdate); // Accessors ghoul::Dictionary getCameraStateDictionary(); @@ -104,15 +68,8 @@ public: glm::quat focusNodeToCameraRotation() const; Camera* camera() const; const InputState& inputState() const; - - /** - * Returns the Lua library that contains all Lua functions available to affect the - * interaction. The functions contained are - * - openspace::luascriptfunctions::setOrigin - * \return The Lua library that contains all Lua functions available to affect the - * interaction - */ - static scripting::LuaLibrary luaLibrary(); + const OrbitalNavigator& orbitalNavigator() const; + KeyframeNavigator& keyframeNavigator() const; // Callback functions void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); @@ -123,47 +80,26 @@ public: void saveCameraStateToFile(const std::string& filepath); void restoreCameraStateFromFile(const std::string& filepath); + /** + * \return The Lua library that contains all Lua functions available to affect the + * interaction + */ + static scripting::LuaLibrary luaLibrary(); private: - using Synchronized = ghoul::Boolean; - - struct KeyInformation { - std::string command; - Synchronized synchronization; - std::string documentation; - }; - - std::string generateJson() const override; - - void setInteractionMode(InteractionMode* interactionMode); - bool _cameraUpdatedFromScript = false; - std::multimap _keyLua; - std::unique_ptr _inputState; Camera* _camera; - InteractionMode* _currentInteractionMode; - - std::shared_ptr _mouseStates; - - std::unique_ptr _orbitalInteractionMode; - std::unique_ptr _globeBrowsingInteractionMode; - std::unique_ptr _keyframeInteractionMode; + std::unique_ptr _orbitalNavigator; + std::unique_ptr _keyframeNavigator; // Properties properties::StringProperty _origin; - properties::OptionProperty _interactionModeOption; - - properties::BoolProperty _rotationalFriction; - properties::BoolProperty _horizontalFriction; - properties::BoolProperty _verticalFriction; - - properties::FloatProperty _sensitivity; - properties::FloatProperty _rapidness; + properties::BoolProperty _useKeyFrameInteraction; }; } // namespace interaction } // namespace openspace -#endif // __OPENSPACE_CORE___INTERACTIONHANDLER___H__ +#endif // __OPENSPACE_CORE___NAVIGATIONHANDLER___H__ diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h new file mode 100644 index 0000000000..bdd97f39ba --- /dev/null +++ b/include/openspace/interaction/orbitalnavigator.h @@ -0,0 +1,197 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ +#define __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace openspace { + +class SceneGraphNode; +class Camera; +class SurfacePositionHandle; + +namespace interaction { + +class OrbitalNavigator : public properties::PropertyOwner { +public: + OrbitalNavigator(); + ~OrbitalNavigator(); + + void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); + void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); + void setFocusNode(SceneGraphNode* focusNode); + void startInterpolateCameraDirection(const Camera& camera); + + bool followingNodeRotation() const; + SceneGraphNode* focusNode() const; + +private: + struct CameraRotationDecomposition { + glm::dquat localRotation; + glm::dquat globalRotation; + }; + + // Properties + properties::BoolProperty _rotationalFriction; + properties::BoolProperty _horizontalFriction; + properties::BoolProperty _verticalFriction; + properties::FloatProperty _followFocusNodeRotationDistance; + properties::FloatProperty _minimumAllowedDistance; + properties::FloatProperty _sensitivity; + properties::FloatProperty _motionLag; + + MouseStates _mouseStates; + + SceneGraphNode* _focusNode = nullptr; + glm::dvec3 _previousFocusNodePosition; + glm::dquat _previousFocusNodeRotation; + + Interpolator _rotateToFocusNodeInterpolator; + Interpolator _followRotationInterpolator; + + /** + * Decomposes the cameras rotation in to a global and a local rotation defined by + * CameraRotationDecomposition. The global rotation defines the rotation so that the + * camera points towards the focus node in the direction opposite to the direction + * out from the surface of the object. The local rotation defines the differential + * from the global to the current total rotation so that + * cameraRotation = globalRotation * localRotation. + */ + CameraRotationDecomposition decomposeCameraRotation( + const glm::dvec3& cameraPosition, + const glm::dquat& cameraRotation, + const glm::dvec3& cameraLookUp, + const glm::dvec3& cameraViewDirection); + + /* + * Perform a camera roll on the local camera rotation + * \returns a local camera rotation modified with a roll. + */ + glm::dquat roll(double deltaTime, const glm::dquat& localCameraRotation) const; + + /** + * Performs rotation around the cameras x and y axes. + * \returns a local camera rotation modified with two degrees of freedom. + */ + glm::dquat rotateLocally(double deltaTime, + const glm::dquat& localCameraRotation) const; + + /** + * Interpolates the local rotation towards a 0 rotation. + * \returns a modified local rotation interpolated towards 0. + */ + glm::dquat interpolateLocalRotation(double deltaTime, + const glm::dquat& localCameraRotation); + + /** + * Translates the horizontal direction. If far from the focus object, this will + * result in an orbital rotation around the object. This function does not affect the + * rotation but only the position. + * \returns a position vector adjusted in the horizontal direction. + */ + glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff, + const glm::dquat& globalCameraRotation, + const SurfacePositionHandle& positionHandle) const; + + /* + * Adds rotation to the camera position so that it follows the rotation of the focus + * node defined by the differential focusNodeRotationDiff. + * \returns a position updated with the rotation defined by focusNodeRotationDiff + */ + glm::dvec3 followFocusNodeRotation(const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff) const; + + /** + * Updates the global rotation so that it points towards the focus node. + * \returns a global rotation quaternion defining a rotation towards the focus node. + */ + glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Translates the camera position towards or away from the focus node. + * \returns a position vector adjusted in the vertical direction. + */ + glm::dvec3 translateVertically(double deltaTime, const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Rotates the camera around the out vector of the surface. + * \returns a quaternion adjusted to rotate around the out vector of the surface. + */ + glm::dquat rotateHorizontally(double deltaTime, + const glm::dquat& globalCameraRotation, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Push the camera out to the surface of the object. + * \returns a position vector adjusted to be at least minHeightAboveGround meters + * above the actual surface of the object + */ + glm::dvec3 pushToSurface(double minHeightAboveGround, + const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const; + + /** + * Interpolates between rotationDiff and a 0 rotation. + */ + glm::dquat interpolateRotationDifferential( + double deltaTime, double interpolationTime, + const glm::dquat& rotationDiff, + const glm::dvec3& objectPosition, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle); + + /** + * Calculates a SurfacePositionHandle given a camera position in world space. + */ + SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3 cameraPositionWorldSpace); +}; + +} // namespace interaction +} // namespace openspace + +#endif // __OPENSPACE_CORE___ORBITALNAVIGATOR___H__ diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index b9fe5cf7a3..a5bafcc8d5 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -42,6 +42,7 @@ namespace openspace { struct RenderData; struct UpdateData; struct RendererTasks; +struct SurfacePositionHandle; namespace documentation { struct Documentation; } @@ -78,6 +79,8 @@ public: virtual void render(const RenderData& data); virtual void render(const RenderData& data, RendererTasks& rendererTask); virtual void update(const UpdateData& data); + virtual SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace); RenderBin renderBin() const; void setRenderBin(RenderBin bin); diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index de8d49b787..7f940aafc7 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -48,6 +48,7 @@ class Translation; class Scale; class Scene; struct UpdateData; +struct SurfacePositionHandle; namespace documentation { struct Documentation; } @@ -91,6 +92,8 @@ public: void removeDependency(SceneGraphNode& dependency, UpdateScene updateScene = UpdateScene::Yes); void clearDependencies(UpdateScene updateScene = UpdateScene::Yes); void setDependencies(const std::vector& dependencies, UpdateScene updateScene = UpdateScene::Yes); + SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace); const std::vector& dependencies() const; const std::vector& dependentNodes() const; diff --git a/include/openspace/util/updatestructures.h b/include/openspace/util/updatestructures.h index 6e0c007e72..47609c7994 100644 --- a/include/openspace/util/updatestructures.h +++ b/include/openspace/util/updatestructures.h @@ -75,6 +75,21 @@ struct RaycastData { std::string namespaceName; }; +/** + * Defines the position of an object relative to a surface. The surface is defined as + * a reference surface together with a height offset from that reference surface. + */ +struct SurfacePositionHandle { + /// Vector from the center of the object to the reference surface of the object + glm::dvec3 centerToReferenceSurface; + /// Direction out from the reference. Can conincide with the surface normal but does + /// not have to. + glm::dvec3 referenceSurfaceOutDirection; + /// Height from the reference surface out to the actual surface in the direction of + /// the surface normal. Can be positive or negative. + double heightToSurface; +}; + } // namespace openspace #endif // __OPENSPACE_CORE___UPDATESTRUCTURES___H__ diff --git a/modules/globebrowsing/chunk/chunk.cpp b/modules/globebrowsing/chunk/chunk.cpp index aafd7a0b2a..dca2d4697d 100644 --- a/modules/globebrowsing/chunk/chunk.cpp +++ b/modules/globebrowsing/chunk/chunk.cpp @@ -102,7 +102,7 @@ Chunk::BoundingHeights Chunk::getBoundingHeights() const { // a single raster image. If it is not we will just use the first raster // (that is channel 0). const size_t HeightChannel = 0; - const LayerGroup& heightmaps = layerManager->layerGroup(layergroupid::HeightLayers); + const LayerGroup& heightmaps = layerManager->layerGroup(layergroupid::GroupID::HeightLayers); std::vector chunkTileSettingPairs = tileselector::getTilesAndSettingsUnsorted( heightmaps, _tileIndex); diff --git a/modules/globebrowsing/geometry/geodeticpatch.h b/modules/globebrowsing/geometry/geodeticpatch.h index e47cd5de3d..eff1392431 100644 --- a/modules/globebrowsing/geometry/geodeticpatch.h +++ b/modules/globebrowsing/geometry/geodeticpatch.h @@ -27,11 +27,10 @@ #include #include +#include namespace openspace { namespace globebrowsing { - -struct TileIndex; class GeodeticPatch { public: diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 546029c3b1..0f5a8c2c24 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -25,8 +25,11 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -37,11 +40,11 @@ #include #include #include - #include #include #include +#include #include #include @@ -51,6 +54,10 @@ #include "globebrowsingmodule_lua.inl" +namespace { + const char* _loggerCat = "GlobeBrowsingModule"; +} + namespace openspace { GlobeBrowsingModule::GlobeBrowsingModule() : OpenSpaceModule(Name) {} @@ -146,6 +153,18 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { "any of " + listLayerGroups + ". The third argument is the dictionary" "defining the layer." }, + { + "goToChunk", + &globebrowsing::luascriptfunctions::goToChunk, + "void", + "Go to chunk with given index x, y, level" + }, + { + "goToGeo", + &globebrowsing::luascriptfunctions::goToGeo, + "void", + "Go to geographic coordinates latitude and longitude" + } }, { "${MODULE_GLOBEBROWSING}/scripts/layer_support.lua" @@ -156,6 +175,163 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { }; } +void GlobeBrowsingModule::goToChunk(int x, int y, int level) { + using namespace globebrowsing; + Camera* cam = OsEng.navigationHandler().camera(); + goToChunk(*cam, TileIndex(x,y,level), glm::vec2(0.5, 0.5), true); +} + +void GlobeBrowsingModule::goToGeo(double latitude, double longitude) { + using namespace globebrowsing; + Camera* cam = OsEng.navigationHandler().camera(); + goToGeodetic2(*cam, Geodetic2(latitude, longitude) / 180 * glm::pi(), true); +} + +void GlobeBrowsingModule::goToGeo(double latitude, double longitude, + double altitude) +{ + using namespace globebrowsing; + + Camera* cam = OsEng.navigationHandler().camera(); + goToGeodetic3( + *cam, + { + Geodetic2(latitude, longitude) / 180 * glm::pi(), + altitude + }, + true + ); +} + +void GlobeBrowsingModule::goToChunk(Camera& camera, globebrowsing::TileIndex ti, + glm::vec2 uv, bool resetCameraDirection) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + // Camera position in model space + glm::dvec3 camPos = camera.positionVec3(); + glm::dmat4 inverseModelTransform = globe->inverseModelTransform(); + glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); + + GeodeticPatch patch(ti); + Geodetic2 corner = patch.getCorner(SOUTH_WEST); + Geodetic2 positionOnPatch = patch.getSize(); + positionOnPatch.lat *= uv.y; + positionOnPatch.lon *= uv.x; + Geodetic2 pointPosition = corner + positionOnPatch; + + glm::dvec3 positionOnEllipsoid = + globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace); + double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); + + goToGeodetic3(camera, {pointPosition, altitude}, resetCameraDirection); +} + +void GlobeBrowsingModule::goToGeodetic2(Camera& camera, + globebrowsing::Geodetic2 geo2, + bool resetCameraDirection) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + // Camera position in model space + glm::dvec3 camPos = camera.positionVec3(); + glm::dmat4 inverseModelTransform = globe->inverseModelTransform(); + glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); + + glm::dvec3 positionOnEllipsoid = + globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace); + double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); + + goToGeodetic3(camera, {geo2, altitude}, resetCameraDirection); +} + +void GlobeBrowsingModule::goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, + bool resetCameraDirection) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianPosition(geo3); + glm::dmat4 modelTransform = globe->modelTransform(); + glm::dvec3 positionWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0); + camera.setPositionVec3(positionWorldSpace); + + if (resetCameraDirection) { + this->resetCameraDirection(camera, geo3.geodetic2); + } +} + +void GlobeBrowsingModule::resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2) +{ + using namespace globebrowsing; + + RenderableGlobe* globe = castFocusNodeRenderableToGlobe(); + if (!globe) { + LERROR("Focus node must have a RenderableGlobe renderable."); + return; + } + + // Camera is described in world space + glm::dmat4 modelTransform = globe->modelTransform(); + + // Lookup vector + glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianSurfacePosition(geo2); + glm::dvec3 slightlyNorth = globe->ellipsoid().cartesianSurfacePosition( + Geodetic2(geo2.lat + 0.001, geo2.lon)); + glm::dvec3 lookUpModelSpace = glm::normalize(slightlyNorth - positionModelSpace); + glm::dvec3 lookUpWorldSpace = glm::dmat3(modelTransform) * lookUpModelSpace; + + // Lookat vector + glm::dvec3 lookAtWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0); + + // Eye position + glm::dvec3 eye = camera.positionVec3(); + + // Matrix + glm::dmat4 lookAtMatrix = glm::lookAt( + eye, lookAtWorldSpace, lookUpWorldSpace); + + // Set rotation + glm::dquat rotation = glm::quat_cast(inverse(lookAtMatrix)); + camera.setRotation(rotation); +} + +globebrowsing::RenderableGlobe* GlobeBrowsingModule::castFocusNodeRenderableToGlobe() { + using namespace globebrowsing; + + Renderable* baseRenderable = OsEng.navigationHandler().focusNode()->renderable(); + if (!baseRenderable) { + return nullptr; + } + if (globebrowsing::RenderableGlobe* globe = + dynamic_cast(baseRenderable)) + { + return globe; + } + else { + return nullptr; + } +} + std::string GlobeBrowsingModule::layerGroupNamesList() { std::string listLayerGroups(""); for (int i = 0; i < globebrowsing::layergroupid::NUM_LAYER_GROUPS - 1; ++i) { diff --git a/modules/globebrowsing/globebrowsingmodule.h b/modules/globebrowsing/globebrowsingmodule.h index 718190c9e0..2faad330ef 100644 --- a/modules/globebrowsing/globebrowsingmodule.h +++ b/modules/globebrowsing/globebrowsingmodule.h @@ -26,11 +26,17 @@ #define __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEBROWSING_MODULE___H__ #include +#include #include namespace openspace { - + class Camera; namespace globebrowsing { + class RenderableGlobe; + class TileIndex; + class Geodetic2; + class Geodetic3; + namespace cache { class MemoryAwareTileCache; } @@ -42,14 +48,26 @@ public: GlobeBrowsingModule(); - globebrowsing::cache::MemoryAwareTileCache* tileCache(); - + void goToChunk(int x, int y, int level); + void goToGeo(double latitude, double longitude); + void goToGeo(double latitude, double longitude, double altitude); + globebrowsing::cache::MemoryAwareTileCache* tileCache(); scripting::LuaLibrary luaLibrary() const override; protected: void internalInitialize() override; private: + + void goToChunk(Camera& camera, globebrowsing::TileIndex ti, glm::vec2 uv, + bool resetCameraDirection); + void goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, + bool resetCameraDirection); + void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3, + bool resetCameraDirection); + void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2); + globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe(); + /** \return a comma separated list of layer group names. */ diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index cd6dbfb9f7..c5fe4bf5db 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -135,6 +136,47 @@ int deleteLayer(lua_State* L) { return 0; } +int goToChunk(lua_State* L) { + using ghoul::lua::luaTypeToString; + + // Check arguments + int nArguments = lua_gettop(L); + if (nArguments != 3) { + return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments); + } + + int x = static_cast(lua_tonumber(L, 1)); + int y = static_cast(lua_tonumber(L, 2)); + int level = static_cast(lua_tonumber(L, 3)); + + OsEng.moduleEngine().module()->goToChunk(x, y, level); + + return 0; +} + +int goToGeo(lua_State* L) { + using ghoul::lua::luaTypeToString; + + int nArguments = lua_gettop(L); + if (nArguments != 2 && nArguments != 3) { + return luaL_error(L, "Expected 2 or 3 arguments."); + } + + double latitude = static_cast(lua_tonumber(L, 1)); + double longitude = static_cast(lua_tonumber(L, 2)); + + if (nArguments == 2) { + OsEng.moduleEngine().module()->goToGeo(latitude, longitude); + } + else if (nArguments == 3) { + double altitude = static_cast(lua_tonumber(L, 3)); + OsEng.moduleEngine().module()->goToGeo(latitude, longitude, + altitude); + } + + return 0; +} + } // namespace luascriptfunctions } // nameapace globebrowsing diff --git a/modules/globebrowsing/globes/chunkedlodglobe.cpp b/modules/globebrowsing/globes/chunkedlodglobe.cpp index 2014f0c20c..60de75ff00 100644 --- a/modules/globebrowsing/globes/chunkedlodglobe.cpp +++ b/modules/globebrowsing/globes/chunkedlodglobe.cpp @@ -174,7 +174,7 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const { // Get the tile providers for the height maps const std::vector>& heightMapLayers = - _layerManager->layerGroup(layergroupid::HeightLayers).activeLayers(); + _layerManager->layerGroup(layergroupid::GroupID::HeightLayers).activeLayers(); for (const std::shared_ptr& layer : heightMapLayers) { tileprovider::TileProvider* tileProvider = layer->tileProvider(); diff --git a/modules/globebrowsing/globes/renderableglobe.cpp b/modules/globebrowsing/globes/renderableglobe.cpp index 38c902841f..6b61e0f7d0 100644 --- a/modules/globebrowsing/globes/renderableglobe.cpp +++ b/modules/globebrowsing/globes/renderableglobe.cpp @@ -32,8 +32,6 @@ namespace { const char* keyFrame = "Frame"; const char* keyRadii = "Radii"; - const char* keyInteractionDepthBelowEllipsoid = "InteractionDepthBelowEllipsoid"; - const char* keyCameraMinHeight = "CameraMinHeight"; const char* keySegmentsPerPatch = "SegmentsPerPatch"; const char* keyLayers = "Layers"; } @@ -86,15 +84,6 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) double patchSegmentsd; dictionary.getValue(keySegmentsPerPatch, patchSegmentsd); int patchSegments = patchSegmentsd; - - if (!dictionary.getValue(keyInteractionDepthBelowEllipsoid, - _interactionDepthBelowEllipsoid)) { - _interactionDepthBelowEllipsoid = 0; - } - - float cameraMinHeight; - dictionary.getValue(keyCameraMinHeight, cameraMinHeight); - _generalProperties.cameraMinHeight.set(cameraMinHeight); // Init layer manager ghoul::Dictionary layersDictionary; @@ -262,8 +251,33 @@ const std::shared_ptr RenderableGlobe::savedCamera() const { return _savedCamera; } -double RenderableGlobe::interactionDepthBelowEllipsoid() { - return _interactionDepthBelowEllipsoid; +SurfacePositionHandle RenderableGlobe::calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) +{ + glm::dvec3 centerToEllipsoidSurface = + _ellipsoid.geodeticSurfaceProjection(targetModelSpace); + glm::dvec3 ellipsoidSurfaceToTarget = targetModelSpace - centerToEllipsoidSurface; + // ellipsoidSurfaceOutDirection will point towards the target, we want the outward + // direction. Therefore it must be flipped in case the target is under the reference + // ellipsoid so that it always points outwards + glm::dvec3 ellipsoidSurfaceOutDirection = glm::normalize(ellipsoidSurfaceToTarget); + if (glm::dot(ellipsoidSurfaceOutDirection, centerToEllipsoidSurface) < 0) { + ellipsoidSurfaceOutDirection *= -1.0; + } + + double heightToSurface = getHeight(targetModelSpace); + heightToSurface = glm::isnan(heightToSurface) ? 0.0 : heightToSurface; + centerToEllipsoidSurface = glm::isnan(glm::length(centerToEllipsoidSurface)) ? + (glm::dvec3(0.0, 1.0, 0.0) * static_cast(boundingSphere())) : + centerToEllipsoidSurface; + ellipsoidSurfaceOutDirection = glm::isnan(glm::length(ellipsoidSurfaceOutDirection)) ? + glm::dvec3(0.0, 1.0, 0.0) : ellipsoidSurfaceOutDirection; + + return { + centerToEllipsoidSurface, + ellipsoidSurfaceOutDirection, + heightToSurface + }; } void RenderableGlobe::setSaveCamera(std::shared_ptr camera) { diff --git a/modules/globebrowsing/globes/renderableglobe.h b/modules/globebrowsing/globes/renderableglobe.h index d4c5071577..73e080b2cc 100644 --- a/modules/globebrowsing/globes/renderableglobe.h +++ b/modules/globebrowsing/globes/renderableglobe.h @@ -107,7 +107,11 @@ public: double interactionDepthBelowEllipsoid(); // Setters - void setSaveCamera(std::shared_ptr camera); + void setSaveCamera(std::shared_ptr camera); + + virtual SurfacePositionHandle calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) override; + private: // Globes. These are renderables inserted in a distance switch so that the heavier // ChunkedLodGlobe does not have to be rendered at far distances. @@ -119,7 +123,6 @@ private: DistanceSwitch _distanceSwitch; std::shared_ptr _savedCamera; - double _interactionDepthBelowEllipsoid; std::string _frame; double _time; diff --git a/modules/globebrowsing/rendering/chunkrenderer.cpp b/modules/globebrowsing/rendering/chunkrenderer.cpp index b8db58132e..f5c931878b 100644 --- a/modules/globebrowsing/rendering/chunkrenderer.cpp +++ b/modules/globebrowsing/rendering/chunkrenderer.cpp @@ -228,9 +228,9 @@ void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& da programObject->setUniform("radiiSquared", glm::vec3(ellipsoid.radiiSquared())); if (_layerManager->layerGroup( - layergroupid::NightLayers).activeLayers().size() > 0 || + layergroupid::GroupID::NightLayers).activeLayers().size() > 0 || _layerManager->layerGroup( - layergroupid::WaterMasks).activeLayers().size() > 0 || + layergroupid::GroupID::WaterMasks).activeLayers().size() > 0 || chunk.owner().generalProperties().atmosphereEnabled || chunk.owner().generalProperties().performShading) { diff --git a/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp b/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp index 407dd8c7c3..12715dff59 100644 --- a/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp +++ b/modules/globebrowsing/rendering/gpu/gpulayergroup.cpp @@ -58,7 +58,7 @@ void GPULayerGroup::bind(ghoul::opengl::ProgramObject* programObject, int pileSize = layerGroup.pileSize(); for (size_t i = 0; i < _gpuActiveLayers.size(); ++i) { // should maybe a proper GPULayer factory - _gpuActiveLayers[i] = (category == layergroupid::HeightLayers) ? + _gpuActiveLayers[i] = (category == layergroupid::GroupID::HeightLayers) ? std::make_unique() : std::make_unique(); std::string nameExtension = "[" + std::to_string(i) + "]."; diff --git a/modules/onscreengui/onscreenguimodule.cpp b/modules/onscreengui/onscreenguimodule.cpp index 397c47204e..af2b515b27 100644 --- a/modules/onscreengui/onscreenguimodule.cpp +++ b/modules/onscreengui/onscreenguimodule.cpp @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -70,7 +70,7 @@ OnScreenGUIModule::OnScreenGUIModule() std::vector res = { &(OsEng.windowWrapper()), &(OsEng.settingsEngine()), - &(OsEng.interactionHandler()), + &(OsEng.navigationHandler()), &(OsEng.renderEngine()), &(OsEng.parallelConnection()), &(OsEng.console()) diff --git a/modules/onscreengui/src/guiorigincomponent.cpp b/modules/onscreengui/src/guiorigincomponent.cpp index 7c732583a8..79dfdc6036 100644 --- a/modules/onscreengui/src/guiorigincomponent.cpp +++ b/modules/onscreengui/src/guiorigincomponent.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -42,7 +42,7 @@ GuiOriginComponent::GuiOriginComponent() {} void GuiOriginComponent::render() { - SceneGraphNode* currentFocus = OsEng.interactionHandler().focusNode(); + SceneGraphNode* currentFocus = OsEng.navigationHandler().focusNode(); std::vector nodes = OsEng.renderEngine().scene()->allSceneGraphNodes(); @@ -70,7 +70,7 @@ void GuiOriginComponent::render() { bool hasChanged = ImGui::Combo("Origin", ¤tPosition, nodeNames.c_str()); if (hasChanged) { OsEng.scriptEngine().queueScript( - "openspace.setPropertyValue('Interaction.origin', '" + + "openspace.setPropertyValue('NavigationHandler.origin', '" + nodes[currentPosition]->name() + "');", scripting::ScriptEngine::RemoteScripting::Yes ); diff --git a/modules/onscreengui/src/guiparallelcomponent.cpp b/modules/onscreengui/src/guiparallelcomponent.cpp index d865f7f0b1..b7435fdd53 100644 --- a/modules/onscreengui/src/guiparallelcomponent.cpp +++ b/modules/onscreengui/src/guiparallelcomponent.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include @@ -83,7 +83,7 @@ void GuiParallelComponent::renderClientWithHost() { renderClientCommon(); const size_t nTimeKeyframes = OsEng.timeManager().nKeyframes(); - const size_t nCameraKeyframes = OsEng.interactionHandler().nKeyframes(); + const size_t nCameraKeyframes = OsEng.navigationHandler().keyframeNavigator().nKeyframes(); std::string timeKeyframeInfo = "TimeKeyframes : " + std::to_string(nTimeKeyframes); std::string cameraKeyframeInfo = "CameraKeyframes : " + std::to_string(nCameraKeyframes); diff --git a/modules/touch/include/TouchInteraction.h b/modules/touch/include/TouchInteraction.h index 9f6a736f45..194ebe55fc 100644 --- a/modules/touch/include/TouchInteraction.h +++ b/modules/touch/include/TouchInteraction.h @@ -31,8 +31,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/modules/touch/src/TouchInteraction.cpp b/modules/touch/src/TouchInteraction.cpp index 135e7f0d44..6819db108a 100644 --- a/modules/touch/src/TouchInteraction.cpp +++ b/modules/touch/src/TouchInteraction.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -530,7 +530,7 @@ void TouchInteraction::computeVelocities(const std::vector& list, co case PICK: { // pick something in the scene as focus node if (_selected.size() == 1 && _selected.at(0).node) { setFocusNode(_selected.at(0).node); - OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode() since TouchInteraction is not subclass of InteractionMode + OsEng.navigationHandler().setFocusNode(_focusNode); // cant do setFocusNode() since TouchInteraction is not subclass of InteractionMode // rotate camera to look at new focus, using slerp quat glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3(); @@ -556,7 +556,7 @@ void TouchInteraction::computeVelocities(const std::vector& list, co void TouchInteraction::step(double dt) { using namespace glm; - setFocusNode(OsEng.interactionHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode) + setFocusNode(OsEng.navigationHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode) if (_focusNode && _camera) { // Create variables from current state dvec3 camPos = _camera->positionVec3(); @@ -776,4 +776,4 @@ void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) { _focusNode = focusNode; } -} // openspace namespace \ No newline at end of file +} // openspace namespace diff --git a/modules/touch/src/TuioEar.cpp b/modules/touch/src/TuioEar.cpp index ae8e22efe9..90f1169fdf 100644 --- a/modules/touch/src/TuioEar.cpp +++ b/modules/touch/src/TuioEar.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -156,4 +156,4 @@ TuioEar::TuioEar() { _tuioClient = new TuioClient(_oscReceiver); _tuioClient->addTuioListener(this); _tuioClient->connect(); -} \ No newline at end of file +} diff --git a/modules/touch/touchmodule.cpp b/modules/touch/touchmodule.cpp index 0d24b34aa6..663a4c2634 100644 --- a/modules/touch/touchmodule.cpp +++ b/modules/touch/touchmodule.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -119,8 +119,8 @@ TouchModule::TouchModule() OsEng.registerModuleCallback( OpenSpaceEngine::CallbackOption::PreSync, [&]() { - touch.setCamera(OsEng.interactionHandler().camera()); - touch.setFocusNode(OsEng.interactionHandler().focusNode()); + touch.setCamera(OsEng.navigationHandler().camera()); + touch.setFocusNode(OsEng.navigationHandler().focusNode()); if (hasNewInput() && OsEng.windowWrapper().isMaster()) { touch.updateStateFromInput(listOfContactPoints, lastProcessed); diff --git a/scripts/common.lua b/scripts/common.lua index d44f11dea4..cf351cdaa7 100644 --- a/scripts/common.lua +++ b/scripts/common.lua @@ -52,18 +52,18 @@ helper.setCommonKeys = function() openspace.bindKey( "f", - helper.property.invert('Interaction.horizontalFriction'), + helper.property.invert('NavigationHandler.OrbitalNavigator.horizontalFriction'), "Toggles the horizontal friction of the camera. If it is disabled, the camera rotates around the focus object indefinitely." ) openspace.bindKey( "Shift+f", - helper.property.invert('Interaction.verticalFriction'), + helper.property.invert('NavigationHandler.OrbitalNavigator.verticalFriction'), "Toggles the vertical friction of the camera. If it is disabled, the camera rises up from or closes in towards the focus object indefinitely." ) openspace.bindKey( "Ctrl+f", - helper.property.invert('Interaction.rotationalFriction'), + helper.property.invert('NavigationHandler.OrbitalNavigator.rotationalFriction'), "Toggles the rotational friction of the camera. If it is disabled, the camera rotates around its own axis indefinitely." ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0ba088f52b..478565e837 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,10 +42,15 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/engine/wrapper/sgctwindowwrapper.cpp ${OPENSPACE_BASE_DIR}/src/engine/wrapper/windowwrapper.cpp ${OPENSPACE_BASE_DIR}/src/interaction/controller.cpp - ${OPENSPACE_BASE_DIR}/src/interaction/interactionhandler.cpp - ${OPENSPACE_BASE_DIR}/src/interaction/interactionmode.cpp - ${OPENSPACE_BASE_DIR}/src/interaction/interactionhandler_lua.inl + ${OPENSPACE_BASE_DIR}/src/interaction/inputstate.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager_lua.inl + ${OPENSPACE_BASE_DIR}/src/interaction/keyframenavigator.cpp ${OPENSPACE_BASE_DIR}/src/interaction/luaconsole.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl + ${OPENSPACE_BASE_DIR}/src/interaction/mousestate.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp ${OPENSPACE_BASE_DIR}/src/mission/mission.cpp ${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp ${OPENSPACE_BASE_DIR}/src/mission/missionmanager_lua.inl @@ -181,9 +186,17 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/sgctwindowwrapper.h ${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/windowwrapper.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/controller.h - ${OPENSPACE_BASE_DIR}/include/openspace/interaction/interactionhandler.h - ${OPENSPACE_BASE_DIR}/include/openspace/interaction/interactionmode.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.inl + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/inputstate.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.inl + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/keybindingmanager.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/keyframenavigator.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/luaconsole.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousestate.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h ${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h ${OPENSPACE_BASE_DIR}/include/openspace/mission/missionmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/network/networkengine.h diff --git a/src/documentation/core_registration.cpp b/src/documentation/core_registration.cpp index 6d7dcba3bf..8539fe5b4e 100644 --- a/src/documentation/core_registration.cpp +++ b/src/documentation/core_registration.cpp @@ -30,7 +30,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -69,7 +70,8 @@ void registerCoreClasses(scripting::ScriptEngine& engine) { engine.addLibrary(RenderEngine::luaLibrary()); engine.addLibrary(Scene::luaLibrary()); engine.addLibrary(Time::luaLibrary()); - engine.addLibrary(interaction::InteractionHandler::luaLibrary()); + engine.addLibrary(interaction::KeyBindingManager::luaLibrary()); + engine.addLibrary(interaction::NavigationHandler::luaLibrary()); engine.addLibrary(ParallelConnection::luaLibrary()); engine.addLibrary(ModuleEngine::luaLibrary()); engine.addLibrary(scripting::ScriptScheduler::luaLibrary()); diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 51149a9df4..35a8f0ba56 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -36,7 +36,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -140,7 +141,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, , _commandlineParser(new ghoul::cmdparser::CommandlineParser( programName, ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes )) - , _interactionHandler(new interaction::InteractionHandler) + , _navigationHandler(new interaction::NavigationHandler) + , _keyBindingManager(new interaction::KeyBindingManager) , _scriptEngine(new scripting::ScriptEngine) , _scriptScheduler(new scripting::ScriptScheduler) , _virtualPropertyManager(new VirtualPropertyManager) @@ -151,10 +153,10 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, , _shutdown({false, 0.f, 0.f}) , _isFirstRenderingFirstFrame(true) { - _interactionHandler->setPropertyOwner(_globalPropertyNamespace.get()); + _navigationHandler->setPropertyOwner(_globalPropertyNamespace.get()); // New property subowners also have to be added to the OnScreenGuiModule callback! - _globalPropertyNamespace->addPropertySubOwner(_interactionHandler.get()); + _globalPropertyNamespace->addPropertySubOwner(_navigationHandler.get()); _globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get()); _globalPropertyNamespace->addPropertySubOwner(_renderEngine.get()); _globalPropertyNamespace->addPropertySubOwner(_windowWrapper.get()); @@ -206,6 +208,7 @@ void OpenSpaceEngine::create(int argc, char** argv, requestClose = false; LDEBUG("Initialize FileSystem"); + ghoul::initialize(); // Initialize the LogManager and add the console log as this will be used every time @@ -219,7 +222,6 @@ void OpenSpaceEngine::create(int argc, char** argv, ); LogMgr.addLog(std::make_unique()); - #ifdef __APPLE__ ghoul::filesystem::File app(argv[0]); std::string dirName = app.directoryName(); @@ -515,9 +517,9 @@ void OpenSpaceEngine::initialize() { _settingsEngine->initialize(); _settingsEngine->setModules(_moduleEngine->modules()); - // Initialize the InteractionHandler - _interactionHandler->initialize(); - + // Initialize the NavigationHandler + _navigationHandler->initialize(); + // Load a light and a monospaced font loadFonts(); @@ -601,7 +603,11 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) { _renderEngine->startFading(1, 3.0); scene->initialize(); - _interactionHandler->setCamera(scene->camera()); + // Update the scene so that position of objects are set in case they are used in + // post sync scripts + _renderEngine->updateScene(); + _navigationHandler->setCamera(scene->camera()); + _navigationHandler->setFocusNode(scene->camera()->parent()); try { runPostInitializationScripts(scenePath); @@ -612,7 +618,7 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) { // Write keyboard documentation. if (configurationManager().hasKey(ConfigurationManager::KeyKeyboardShortcuts)) { - interactionHandler().writeDocumentation( + keyBindingManager().writeDocumentation( absPath(configurationManager().value( ConfigurationManager::KeyKeyboardShortcuts )) @@ -638,7 +644,7 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) { void OpenSpaceEngine::deinitialize() { LTRACE("OpenSpaceEngine::deinitialize(begin)"); - _interactionHandler->deinitialize(); + _navigationHandler->deinitialize(); _renderEngine->deinitialize(); LTRACE("OpenSpaceEngine::deinitialize(end)"); @@ -1120,10 +1126,8 @@ void OpenSpaceEngine::preSynchronization() { ); } - _interactionHandler->updateInputStates(dt); - _renderEngine->updateScene(); - _interactionHandler->updateCamera(dt); + _navigationHandler->updateCamera(dt); _renderEngine->camera()->invalidateCache(); _parallelConnection->preSynchronization(); @@ -1158,9 +1162,6 @@ void OpenSpaceEngine::postSynchronizationPreDraw() { _renderEngine->camera()->invalidateCache(); } - // Step the camera using the current mouse velocities which are synced - //_interactionHandler->updateCamera(); - for (const auto& func : _moduleCallbacks.postSyncPreDraw) { func(); } @@ -1250,7 +1251,8 @@ void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction actio return; } - _interactionHandler->keyboardCallback(key, mod, action); + _navigationHandler->keyboardCallback(key, mod, action); + _keyBindingManager->keyboardCallback(key, mod, action); } void OpenSpaceEngine::charCallback(unsigned int codepoint, KeyModifier modifier) { @@ -1272,7 +1274,7 @@ void OpenSpaceEngine::mouseButtonCallback(MouseButton button, MouseAction action } } - _interactionHandler->mouseButtonCallback(button, action); + _navigationHandler->mouseButtonCallback(button, action); } void OpenSpaceEngine::mousePositionCallback(double x, double y) { @@ -1280,7 +1282,7 @@ void OpenSpaceEngine::mousePositionCallback(double x, double y) { func(x, y); } - _interactionHandler->mousePositionCallback(x, y); + _navigationHandler->mousePositionCallback(x, y); } void OpenSpaceEngine::mouseScrollWheelCallback(double posX, double posY) { @@ -1291,7 +1293,7 @@ void OpenSpaceEngine::mouseScrollWheelCallback(double posX, double posY) { } } - _interactionHandler->mouseScrollWheelCallback(posY); + _navigationHandler->mouseScrollWheelCallback(posY); } void OpenSpaceEngine::encode() { @@ -1501,9 +1503,14 @@ ghoul::fontrendering::FontManager& OpenSpaceEngine::fontManager() { return *_fontManager; } -interaction::InteractionHandler& OpenSpaceEngine::interactionHandler() { - ghoul_assert(_interactionHandler, "InteractionHandler must not be nullptr"); - return *_interactionHandler; +interaction::NavigationHandler& OpenSpaceEngine::navigationHandler() { + ghoul_assert(_navigationHandler, "NavigationHandler must not be nullptr"); + return *_navigationHandler; +} + +interaction::KeyBindingManager& OpenSpaceEngine::keyBindingManager() { + ghoul_assert(_keyBindingManager, "KeyBindingManager must not be nullptr"); + return *_keyBindingManager; } properties::PropertyOwner& OpenSpaceEngine::globalPropertyOwner() { diff --git a/src/interaction/controller.cpp b/src/interaction/controller.cpp index 5e844f6a1d..a7bc2549ea 100644 --- a/src/interaction/controller.cpp +++ b/src/interaction/controller.cpp @@ -24,12 +24,12 @@ #include -#include +#include namespace openspace { namespace interaction { -void Controller::setHandler(InteractionHandler* handler) +void Controller::setHandler(NavigationHandler* handler) { _handler = handler; } diff --git a/src/interaction/inputstate.cpp b/src/interaction/inputstate.cpp new file mode 100644 index 0000000000..93c29b204c --- /dev/null +++ b/src/interaction/inputstate.cpp @@ -0,0 +1,97 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +#include + +namespace openspace { +namespace interaction { + +void InputState::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { + if (action == KeyAction::Press) { + _keysDown.emplace_back(key, modifier); + } + else if (action == KeyAction::Release) { + // Remove all key pressings for 'key' + _keysDown.remove_if([key](std::pair keyModPair) + { return keyModPair.first == key; }); + } +} + +void InputState::mouseButtonCallback(MouseButton button, MouseAction action) { + if (action == MouseAction::Press) { + _mouseButtonsDown.push_back(button); + } + else if (action == MouseAction::Release) { + // Remove all key pressings for 'button' + _mouseButtonsDown.remove_if([button](MouseButton buttonInList) + { return button == buttonInList; }); + } +} + +void InputState::mousePositionCallback(double mouseX, double mouseY) { + _mousePosition = glm::dvec2(mouseX, mouseY); +} + +void InputState::mouseScrollWheelCallback(double mouseScrollDelta) { + _mouseScrollDelta = mouseScrollDelta; +} + +const std::list >& InputState::getPressedKeys() const { + return _keysDown; +} + +const std::list& InputState::getPressedMouseButtons() const { + return _mouseButtonsDown; +} + +glm::dvec2 InputState::getMousePosition() const { + return _mousePosition; +} + +double InputState::getMouseScrollDelta() const { + return _mouseScrollDelta; +} + +bool InputState::isKeyPressed(std::pair keyModPair) const { + return std::find(_keysDown.begin(), _keysDown.end(), keyModPair) != _keysDown.end(); +} + +bool InputState::isKeyPressed(Key key) const { + return std::find_if(_keysDown.begin(), _keysDown.end(), + [key](const std::pair& keyModPair) { + return key == keyModPair.first; + }) != _keysDown.end(); +} + +bool InputState::isMouseButtonPressed(MouseButton mouseButton) const { + return std::find(_mouseButtonsDown.begin(), _mouseButtonsDown.end(), + mouseButton) != _mouseButtonsDown.end(); +} + +} // namespace interaction +} // namespace openspace diff --git a/src/interaction/interactionhandler.cpp b/src/interaction/interactionhandler.cpp deleted file mode 100644 index 76b9817bd7..0000000000 --- a/src/interaction/interactionhandler.cpp +++ /dev/null @@ -1,563 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -#include -#endif - -#include - -#include - -namespace { - const char* _loggerCat = "InteractionHandler"; - - const char* KeyFocus = "Focus"; - const char* KeyPosition = "Position"; - const char* KeyRotation = "Rotation"; - - const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/main.hbs"; - const char* KeybindingTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/keybinding.hbs"; - const char* JsFilename = "${OPENSPACE_DATA}/web/keybindings/script.js"; - - const int IdOrbitalInteractionMode = 0; - const char* KeyOrbitalInteractionMode = "Orbital"; - - const int IdGlobeBrowsingInteractionMode = 1; - const char* KeyGlobeBrowsingInteractionMode = "GlobeBrowsing"; - - const int IdKeyframeInteractionMode = 2; - const char* KeyKeyframeInteractionMode = "Keyframe"; -} // namespace - -#include "interactionhandler_lua.inl" - -namespace openspace { -namespace interaction { - -// InteractionHandler -InteractionHandler::InteractionHandler() - : properties::PropertyOwner("Interaction") - , DocumentationGenerator( - "Documentation", - "keybindings", - { - { "keybindingTemplate", KeybindingTemplateFilename }, - { "mainTemplate", MainTemplateFilename } - }, - JsFilename - ) - , _origin("origin", "Origin", "") - , _rotationalFriction("rotationalFriction", "Rotational Friction", true) - , _horizontalFriction("horizontalFriction", "Horizontal Friction", true) - , _verticalFriction("verticalFriction", "Vertical Friction", true) - , _sensitivity("sensitivity", "Sensitivity", 0.5f, 0.001f, 1.f) - , _rapidness("rapidness", "Rapidness", 1.f, 0.1f, 60.f) - , _interactionModeOption( - "interactionMode", - "Interaction Mode", - properties::OptionProperty::DisplayType::Dropdown - ) -{ - _origin.onChange([this]() { - SceneGraphNode* node = sceneGraphNode(_origin.value()); - if (!node) { - LWARNING("Could not find a node in scenegraph called '" << _origin.value() << "'"); - return; - } - setFocusNode(node); - resetCameraDirection(); - }); - - // Create the interactionModes - _inputState = std::make_unique(); - // Inject the same mouse states to both orbital and global interaction mode - _mouseStates = std::make_unique(_sensitivity * pow(10.0,-4), 1); - - _orbitalInteractionMode = std::make_unique(_mouseStates); - _globeBrowsingInteractionMode = std::make_unique(_mouseStates); - _keyframeInteractionMode = std::make_unique(); - - _interactionModeOption.addOption(IdOrbitalInteractionMode, KeyOrbitalInteractionMode); - _interactionModeOption.addOption(IdGlobeBrowsingInteractionMode, KeyGlobeBrowsingInteractionMode); - _interactionModeOption.addOption(IdKeyframeInteractionMode, KeyKeyframeInteractionMode); - - // Set the interactionMode - _currentInteractionMode = _orbitalInteractionMode.get(); - - // Define lambda functions for changed properties - _rotationalFriction.onChange([&]() { - _mouseStates->setRotationalFriction(_rotationalFriction); - }); - _horizontalFriction.onChange([&]() { - _mouseStates->setHorizontalFriction(_horizontalFriction); - }); - _verticalFriction.onChange([&]() { - _mouseStates->setVerticalFriction(_verticalFriction); - }); - _sensitivity.onChange([&]() { - _mouseStates->setSensitivity(_sensitivity * pow(10.0,-4)); - }); - _rapidness.onChange([&]() { - _mouseStates->setVelocityScaleFactor(_rapidness); - }); - - _interactionModeOption.onChange([this]() { - switch(_interactionModeOption.value()) { - case IdGlobeBrowsingInteractionMode: - setInteractionMode(_globeBrowsingInteractionMode.get()); - break; - case IdKeyframeInteractionMode: - setInteractionMode(_keyframeInteractionMode.get()); - break; - case IdOrbitalInteractionMode: - default: - setInteractionMode(_orbitalInteractionMode.get()); - break; - } - }); - - - // Add the properties - addProperty(_origin); - addProperty(_interactionModeOption); - - addProperty(_rotationalFriction); - addProperty(_horizontalFriction); - addProperty(_verticalFriction); - addProperty(_sensitivity); - addProperty(_rapidness); -} - -InteractionHandler::~InteractionHandler() { - -} - -void InteractionHandler::initialize() { - OsEng.parallelConnection().connectionEvent()->subscribe("interactionHandler", "statusChanged", [this]() { - if (OsEng.parallelConnection().status() == ParallelConnection::Status::ClientWithHost) { - setInteractionMode(_keyframeInteractionMode.get()); - } else if (_currentInteractionMode == _keyframeInteractionMode.get()) { - setInteractionMode(_orbitalInteractionMode.get()); - } - }); -} - -void InteractionHandler::deinitialize() { - OsEng.parallelConnection().connectionEvent()->unsubscribe("interactionHandler"); -} - -void InteractionHandler::setFocusNode(SceneGraphNode* node) { - _currentInteractionMode->setFocusNode(node); -} - -void InteractionHandler::setCamera(Camera* camera) { - _camera = camera; - setFocusNode(_camera->parent()); -} - -void InteractionHandler::resetCameraDirection() { - LINFO("Setting camera direction to point at focus node."); - _currentInteractionMode->rotateToFocusNodeInterpolator().start(); -} - -void InteractionHandler::setInteractionMode(InteractionMode* interactionMode) { - // Focus node is passed over from the previous interaction mode - SceneGraphNode* focusNode = _currentInteractionMode->focusNode(); - - // Set the interaction mode - _currentInteractionMode = interactionMode; - - // Update the focusnode for the new interaction mode - _currentInteractionMode->setFocusNode(focusNode); -} - -InteractionMode * InteractionHandler::interactionMode() { - return _currentInteractionMode; -} - -void InteractionHandler::goToChunk(int x, int y, int level) { - if (_currentInteractionMode == _globeBrowsingInteractionMode.get()) { -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - _globeBrowsingInteractionMode->goToChunk(*_camera, globebrowsing::TileIndex(x,y,level), glm::vec2(0.5,0.5), true); -#endif - } else { - LWARNING("Interaction mode must be set to 'GlobeBrowsing'"); - } -} - -void InteractionHandler::goToGeo(double latitude, double longitude) { - if (_currentInteractionMode == _globeBrowsingInteractionMode.get()) { -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - _globeBrowsingInteractionMode->goToGeodetic2( - *_camera, - globebrowsing::Geodetic2(latitude, longitude) / 180 * glm::pi(), true - ); -#endif - } else { - LWARNING("Interaction mode must be set to 'GlobeBrowsing'"); - } -} - -void InteractionHandler::lockControls() { - -} - -void InteractionHandler::unlockControls() { - -} - -void InteractionHandler::updateInputStates(double timeSinceLastUpdate) { - ghoul_assert(_inputState != nullptr, "InputState cannot be null!"); - ghoul_assert(_camera != nullptr, "Camera cannot be null!"); - _currentInteractionMode->updateMouseStatesFromInput(*_inputState, timeSinceLastUpdate); -} - -void InteractionHandler::updateCamera(double deltaTime) { - ghoul_assert(_inputState != nullptr, "InputState cannot be null!"); - ghoul_assert(_camera != nullptr, "Camera cannot be null!"); - - if (_cameraUpdatedFromScript) { - _cameraUpdatedFromScript = false; - } - else { - if (_camera && focusNode()) { - _currentInteractionMode->updateCameraStateFromMouseStates(*_camera, deltaTime); - _camera->setFocusPositionVec3(focusNode()->worldPosition()); - } - } -} - -SceneGraphNode* InteractionHandler::focusNode() const { - return _currentInteractionMode->focusNode(); -} - -glm::dvec3 InteractionHandler::focusNodeToCameraVector() const { - return _camera->positionVec3() - focusNode()->worldPosition(); -} - -glm::quat InteractionHandler::focusNodeToCameraRotation() const { - glm::dmat4 invWorldRotation = glm::inverse(focusNode()->worldRotationMatrix()); - return glm::quat(invWorldRotation) * glm::quat(_camera->rotationQuaternion()); -} - -Camera* InteractionHandler::camera() const { - return _camera; -} - -const InputState& InteractionHandler::inputState() const { - return *_inputState; -} - - -void InteractionHandler::mouseButtonCallback(MouseButton button, MouseAction action) { - _inputState->mouseButtonCallback(button, action); -} - -void InteractionHandler::mousePositionCallback(double x, double y) { - _inputState->mousePositionCallback(x, y); -} - -void InteractionHandler::mouseScrollWheelCallback(double pos) { - _inputState->mouseScrollWheelCallback(pos); -} - -void InteractionHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { - _inputState->keyboardCallback(key, modifier, action); - - if (action == KeyAction::Press || action == KeyAction::Repeat) { - // iterate over key bindings - auto ret = _keyLua.equal_range({ key, modifier }); - for (auto it = ret.first; it != ret.second; ++it) { - auto remote = it->second.synchronization ? - scripting::ScriptEngine::RemoteScripting::Yes : - scripting::ScriptEngine::RemoteScripting::No; - - OsEng.scriptEngine().queueScript(it->second.command, remote); - } - } -} - -void InteractionHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict) { - bool readSuccessful = true; - - std::string focus; - glm::dvec3 cameraPosition; - glm::dvec4 cameraRotation; // Need to read the quaternion as a vector first. - - readSuccessful &= cameraDict.getValue(KeyFocus, focus); - readSuccessful &= cameraDict.getValue(KeyPosition, cameraPosition); - readSuccessful &= cameraDict.getValue(KeyRotation, cameraRotation); - - if (!readSuccessful) { - throw ghoul::RuntimeError( - "Position, Rotation and Focus need to be defined for camera dictionary."); - } - - SceneGraphNode* node = sceneGraphNode(focus); - if (!node) { - throw ghoul::RuntimeError( - "Could not find a node in scenegraph called '" + focus + "'"); - } - - // Set state - setFocusNode(node); - _camera->setPositionVec3(cameraPosition); - _camera->setRotation(glm::dquat( - cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w)); -} - -ghoul::Dictionary InteractionHandler::getCameraStateDictionary() { - glm::dvec3 cameraPosition; - glm::dquat quat; - glm::dvec4 cameraRotation; - - cameraPosition = _camera->positionVec3(); - quat = _camera->rotationQuaternion(); - cameraRotation = glm::dvec4(quat.w, quat.x, quat.y, quat.z); - - ghoul::Dictionary cameraDict; - cameraDict.setValue(KeyPosition, cameraPosition); - cameraDict.setValue(KeyRotation, cameraRotation); - cameraDict.setValue(KeyFocus, focusNode()->name()); - - return cameraDict; -} - -void InteractionHandler::saveCameraStateToFile(const std::string& filepath) { - if (!filepath.empty()) { - auto fullpath = absPath(filepath); - LINFO("Saving camera position: " << filepath); - - ghoul::Dictionary cameraDict = getCameraStateDictionary(); - - // TODO : Should get the camera state as a dictionary and save the dictionary to - // a file in form of a lua state and not use ofstreams here. - - std::ofstream ofs(fullpath.c_str()); - - glm::dvec3 p = _camera->positionVec3(); - glm::dquat q = _camera->rotationQuaternion(); - - ofs << "return {" << std::endl; - ofs << " " << KeyFocus << " = " << "\"" << focusNode()->name() << "\"" << "," << std::endl; - ofs << " " << KeyPosition << " = {" - << std::to_string(p.x) << ", " - << std::to_string(p.y) << ", " - << std::to_string(p.z) << "}," << std::endl; - ofs << " " << KeyRotation << " = {" - << std::to_string(q.w) << ", " - << std::to_string(q.x) << ", " - << std::to_string(q.y) << ", " - << std::to_string(q.z) << "}," << std::endl; - ofs << "}"<< std::endl; - - ofs.close(); - } -} - -void InteractionHandler::restoreCameraStateFromFile(const std::string& filepath) { - LINFO("Reading camera state from file: " << filepath); - if (!FileSys.fileExists(filepath)) - throw ghoul::FileNotFoundError(filepath, "CameraFilePath"); - - ghoul::Dictionary cameraDict; - try { - ghoul::lua::loadDictionaryFromFile(filepath, cameraDict); - setCameraStateFromDictionary(cameraDict); - _cameraUpdatedFromScript = true; - } - catch (ghoul::RuntimeError& e) { - LWARNING("Unable to set camera position"); - LWARNING(e.message); - } -} - -void InteractionHandler::resetKeyBindings() { - _keyLua.clear(); -} - -void InteractionHandler::bindKeyLocal(Key key, KeyModifier modifier, - std::string luaCommand, std::string documentation) -{ - _keyLua.insert({ - { key, modifier }, - { std::move(luaCommand), Synchronized::No, std::move(documentation) } - }); -} - -void InteractionHandler::bindKey(Key key, KeyModifier modifier, - std::string luaCommand, std::string documentation) -{ - _keyLua.insert({ - { key, modifier }, - { std::move(luaCommand), Synchronized::Yes, std::move(documentation) } - }); -} - - -std::string InteractionHandler::generateJson() const { - std::stringstream json; - json << "["; - bool first = true; - for (const auto& p : _keyLua) { - if (!first) { - json << ","; - } - first = false; - json << "{"; - json << "\"key\": \"" << std::to_string(p.first) << "\","; - json << "\"script\": \"" << p.second.command << "\","; - json << "\"remoteScripting\": " << (p.second.synchronization ? "true," : "false,"); - json << "\"documentation\": \"" << p.second.documentation << "\""; - json << "}"; - } - json << "]"; - - std::string jsonString = ""; - for (const char& c : json.str()) { - if (c == '\'') { - jsonString += "\\'"; - } else { - jsonString += c; - } - } - - return jsonString; -} - - -scripting::LuaLibrary InteractionHandler::luaLibrary() { - return{ - "", - { - { - "clearKeys", - &luascriptfunctions::clearKeys, - "", - "Clear all key bindings" - }, - { - "bindKey", - &luascriptfunctions::bindKey, - "string, string [,string]", - "Binds a key by name to a lua string command to execute both locally " - "and to broadcast to clients if this is the host of a parallel session. " - "The first argument is the key, the second argument is the Lua command " - "that is to be executed, and the optional third argument is a human " - "readable description of the command for documentation purposes." - }, - { - "bindKeyLocal", - &luascriptfunctions::bindKeyLocal, - "string, string [,string]", - "Binds a key by name to a lua string command to execute only locally. " - "The first argument is the key, the second argument is the Lua command " - "that is to be executed, and the optional third argument is a human " - "readable description of the command for documentation purposes." - }, - { - "saveCameraStateToFile", - &luascriptfunctions::saveCameraStateToFile, - "string", - "Save the current camera state to file" - }, - { - "restoreCameraStateFromFile", - &luascriptfunctions::restoreCameraStateFromFile, - "string", - "Restore the camera state from file" - }, - { - "resetCameraDirection", - &luascriptfunctions::resetCameraDirection, - "void", - "Reset the camera direction to point at the focus node" - }, - { - "goToChunk", - &luascriptfunctions::goToChunk, - "void", - "Go to chunk with given index x, y, level" - }, - { - "goToGeo", - &luascriptfunctions::goToGeo, - "void", - "Go to geographic coordinates latitude and longitude" - }, - } - }; -} - -void InteractionHandler::addKeyframe(double timestamp, KeyframeInteractionMode::CameraPose pose) { - if (!_keyframeInteractionMode) { - return; - } - _keyframeInteractionMode->timeline().addKeyframe(timestamp, pose); -} - -void InteractionHandler::removeKeyframesAfter(double timestamp) { - if (!_keyframeInteractionMode) { - return; - } - _keyframeInteractionMode->timeline().removeKeyframesAfter(timestamp); -} - -void InteractionHandler::clearKeyframes() { - if (!_keyframeInteractionMode) { - return; - } - _keyframeInteractionMode->timeline().clearKeyframes(); -} - -size_t InteractionHandler::nKeyframes() const { - if (!_keyframeInteractionMode) { - return 0; - } - return _keyframeInteractionMode->timeline().keyframes().size(); -} - -} // namespace interaction -} // namespace openspace diff --git a/src/interaction/interactionmode.cpp b/src/interaction/interactionmode.cpp deleted file mode 100644 index 1c487230ec..0000000000 --- a/src/interaction/interactionmode.cpp +++ /dev/null @@ -1,800 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2017 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -#include -#include -#include -#endif - -#include - -namespace { - const std::string _loggerCat = "InteractionMode"; -} - -namespace openspace { -namespace interaction { - - // InputState - InputState::InputState() { - - } - - InputState::~InputState() { - - } - - void InputState::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { - if (action == KeyAction::Press) { - _keysDown.push_back(std::pair(key, modifier)); - } - else if (action == KeyAction::Release) { - // Remove all key pressings for 'key' - _keysDown.remove_if([key](std::pair keyModPair) - { return keyModPair.first == key; }); - } - } - - void InputState::mouseButtonCallback(MouseButton button, MouseAction action) { - if (action == MouseAction::Press) { - _mouseButtonsDown.push_back(button); - } - else if (action == MouseAction::Release) { - // Remove all key pressings for 'button' - _mouseButtonsDown.remove_if([button](MouseButton buttonInList) - { return button == buttonInList; }); - } - } - - void InputState::mousePositionCallback(double mouseX, double mouseY) { - _mousePosition = glm::dvec2(mouseX, mouseY); - } - - void InputState::mouseScrollWheelCallback(double mouseScrollDelta) { - _mouseScrollDelta = mouseScrollDelta; - } - - const std::list >& InputState::getPressedKeys() const { - return _keysDown; - } - - const std::list& InputState::getPressedMouseButtons() const { - return _mouseButtonsDown; - } - - glm::dvec2 InputState::getMousePosition() const { - return _mousePosition; - } - - double InputState::getMouseScrollDelta() const { - return _mouseScrollDelta; - } - - bool InputState::isKeyPressed(std::pair keyModPair) const { - for (auto it = _keysDown.begin(); it != _keysDown.end(); it++) { - if (*it == keyModPair) { - return true; - } - } - return false; - } - - bool InputState::isKeyPressed(Key key) const { - for (auto it = _keysDown.begin(); it != _keysDown.end(); it++) { - if ((*it).first == key) { - return true; - } - } - return false; - } - - bool InputState::isMouseButtonPressed(MouseButton mouseButton) const { - for (auto it = _mouseButtonsDown.begin(); it != _mouseButtonsDown.end(); it++) { - if (*it == mouseButton) { - return true; - } - } - return false; - } - - - -InteractionMode::InteractionMode() - : _rotateToFocusNodeInterpolator(Interpolator([](double t){ - return pow(t, 2); - })) { -} - - -InteractionMode::~InteractionMode() { - -} - -void InteractionMode::setFocusNode(SceneGraphNode* focusNode) { - _focusNode = focusNode; - - if (_focusNode != nullptr) { - _previousFocusNodePosition = _focusNode->worldPosition(); - _previousFocusNodeRotation = glm::quat_cast(_focusNode->worldRotationMatrix()); - } -} - -SceneGraphNode* InteractionMode::focusNode() { - return _focusNode; -} - -Interpolator& InteractionMode::rotateToFocusNodeInterpolator() { - return _rotateToFocusNodeInterpolator; -}; - - -// KeyframeInteractionMode -KeyframeInteractionMode::KeyframeInteractionMode() -{ -} - -KeyframeInteractionMode::~KeyframeInteractionMode() { -} - - -void KeyframeInteractionMode::updateMouseStatesFromInput(const InputState&, double) { - // Do nothing. -} - -void KeyframeInteractionMode::updateCameraStateFromMouseStates(Camera& camera, double) { - double now = OsEng.runTime(); - - if (_cameraPoseTimeline.nKeyframes() == 0) { - return; - } - - const Keyframe* nextKeyframe = _cameraPoseTimeline.firstKeyframeAfter(now); - const Keyframe* prevKeyframe = _cameraPoseTimeline.lastKeyframeBefore(now); - double nextTime = 0; - double prevTime = 0; - double t = 0; - - if (nextKeyframe) { - nextTime = nextKeyframe->timestamp; - } else { - return; - } - - if (prevKeyframe) { - prevTime = prevKeyframe->timestamp; - t = (now - prevTime) / (nextTime - prevTime); - } else { - // If there is no keyframe before: Only use the next keyframe. - prevTime = nextTime; - prevKeyframe = nextKeyframe; - t = 1; - } - - _cameraPoseTimeline.removeKeyframesBefore(prevTime); - - const CameraPose& prevPose = prevKeyframe->data; - const CameraPose& nextPose = nextKeyframe->data; - - Scene* scene = camera.parent()->scene(); - SceneGraphNode* prevFocusNode = scene->sceneGraphNode(prevPose.focusNode); - SceneGraphNode* nextFocusNode = scene->sceneGraphNode(nextPose.focusNode); - - if (!prevFocusNode || !nextFocusNode) { - return; - } - - glm::dvec3 prevKeyframeCameraPosition = prevPose.position; - glm::dvec3 nextKeyframeCameraPosition = nextPose.position; - glm::dquat prevKeyframeCameraRotation = prevPose.rotation; - glm::dquat nextKeyframeCameraRotation = nextPose.rotation; - - // Transform position and rotation based on focus node rotation (if following rotation) - if (prevPose.followFocusNodeRotation) { - prevKeyframeCameraRotation = prevFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(prevPose.rotation)); - prevKeyframeCameraPosition = prevFocusNode->worldRotationMatrix() * prevPose.position; - } - if (nextPose.followFocusNodeRotation) { - nextKeyframeCameraRotation = nextFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(nextPose.rotation)); - nextKeyframeCameraPosition = nextFocusNode->worldRotationMatrix() * nextPose.position; - } - - // Transform position based on focus node position - prevKeyframeCameraPosition += prevFocusNode->worldPosition(); - nextKeyframeCameraPosition += nextFocusNode->worldPosition(); - - // Linear interpolation - camera.setPositionVec3(prevKeyframeCameraPosition * (1 - t) + nextKeyframeCameraPosition * t); - camera.setRotation(glm::slerp(prevKeyframeCameraRotation, nextKeyframeCameraRotation, t)); -} - -bool KeyframeInteractionMode::followingNodeRotation() const { - return false; -} - -Timeline& KeyframeInteractionMode::timeline() { - return _cameraPoseTimeline; -} - -// OrbitalInteractionMode -OrbitalInteractionMode::MouseStates::MouseStates(double sensitivity, double velocityScaleFactor) - : _sensitivity(sensitivity) - , _globalRotationMouseState(velocityScaleFactor) - , _localRotationMouseState(velocityScaleFactor) - , _truckMovementMouseState(velocityScaleFactor) - , _localRollMouseState(velocityScaleFactor) - , _globalRollMouseState(velocityScaleFactor) -{} - -void OrbitalInteractionMode::MouseStates::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) { -#ifdef OPENSPACE_MODULE_TOUCH_ENABLED - ghoul::any t = property("Global Properties.Touch.TouchInteraction.TouchEvents")->get(); - if (!*(ghoul::any_cast(&t))) { -#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - glm::dvec2 mousePosition = inputState.getMousePosition(); - - bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); - bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2); - bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3); - bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl); - bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift); - - // Update the mouse states - if (button1Pressed && !keyShiftPressed) { - if (keyCtrlPressed) { - glm::dvec2 mousePositionDelta = - _localRotationMouseState.previousPosition - mousePosition; - _localRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - - _globalRotationMouseState.previousPosition = mousePosition; - _globalRotationMouseState.velocity.decelerate(deltaTime); - } - else { - glm::dvec2 mousePositionDelta = - _globalRotationMouseState.previousPosition - mousePosition; - _globalRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - - _localRotationMouseState.previousPosition = mousePosition; - _localRotationMouseState.velocity.decelerate(deltaTime); - } - } - else { // !button1Pressed - _localRotationMouseState.previousPosition = mousePosition; - _localRotationMouseState.velocity.decelerate(deltaTime); - - _globalRotationMouseState.previousPosition = mousePosition; - _globalRotationMouseState.velocity.decelerate(deltaTime); - } - if (button2Pressed) { - glm::dvec2 mousePositionDelta = - _truckMovementMouseState.previousPosition - mousePosition; - _truckMovementMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - } - else { // !button2Pressed - _truckMovementMouseState.previousPosition = mousePosition; - _truckMovementMouseState.velocity.decelerate(deltaTime); - } - if (button3Pressed || (keyShiftPressed && button1Pressed)) { - if (keyCtrlPressed) { - glm::dvec2 mousePositionDelta = - _localRollMouseState.previousPosition - mousePosition; - _localRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - - _globalRollMouseState.previousPosition = mousePosition; - _globalRollMouseState.velocity.decelerate(deltaTime); - } - else { - glm::dvec2 mousePositionDelta = - _globalRollMouseState.previousPosition - mousePosition; - _globalRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime); - - _localRollMouseState.previousPosition = mousePosition; - _localRollMouseState.velocity.decelerate(deltaTime); - } - } - else { // !button3Pressed - _globalRollMouseState.previousPosition = mousePosition; - _globalRollMouseState.velocity.decelerate(deltaTime); - - _localRollMouseState.previousPosition = mousePosition; - _localRollMouseState.velocity.decelerate(deltaTime); - } -#ifdef OPENSPACE_MODULE_TOUCH_ENABLED - } -#endif // OPENSPACE_MODULE_TOUCH_ENABLED - -} - -void OrbitalInteractionMode::MouseStates::setRotationalFriction(double friction) { - _localRotationMouseState.setFriction(friction); - _localRollMouseState.setFriction(friction); - _globalRollMouseState.setFriction(friction); -} - -void OrbitalInteractionMode::MouseStates::setHorizontalFriction(double friction) { - _globalRotationMouseState.setFriction(friction); -} - -void OrbitalInteractionMode::MouseStates::setVerticalFriction(double friction) { - _truckMovementMouseState.setFriction(friction); -} - -void OrbitalInteractionMode::MouseStates::setSensitivity(double sensitivity) { - _sensitivity = sensitivity; -} - -void OrbitalInteractionMode::MouseStates::setVelocityScaleFactor(double scaleFactor) { - _globalRotationMouseState.setVelocityScaleFactor(scaleFactor); - _localRotationMouseState.setVelocityScaleFactor(scaleFactor); - _truckMovementMouseState.setVelocityScaleFactor(scaleFactor); - _localRollMouseState.setVelocityScaleFactor(scaleFactor); - _globalRollMouseState.setVelocityScaleFactor(scaleFactor); -} - -glm::dvec2 OrbitalInteractionMode::MouseStates::synchedGlobalRotationMouseVelocity() { - return _globalRotationMouseState.velocity.get(); -} - -glm::dvec2 OrbitalInteractionMode::MouseStates::synchedLocalRotationMouseVelocity() { - return _localRotationMouseState.velocity.get(); -} - -glm::dvec2 OrbitalInteractionMode::MouseStates::synchedTruckMovementMouseVelocity() { - return _truckMovementMouseState.velocity.get(); -} - -glm::dvec2 OrbitalInteractionMode::MouseStates::synchedLocalRollMouseVelocity() { - return _localRollMouseState.velocity.get(); -} - -glm::dvec2 OrbitalInteractionMode::MouseStates::synchedGlobalRollMouseVelocity() { - return _globalRollMouseState.velocity.get(); -} - -OrbitalInteractionMode::OrbitalInteractionMode( - std::shared_ptr mouseStates) - : InteractionMode() - , _mouseStates(mouseStates) { - -} - -OrbitalInteractionMode::~OrbitalInteractionMode() { - -} - -void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera, double deltaTime) { - // Update synched data - - using namespace glm; - if (_focusNode) { - // Read the current state of the camera and focus node - dvec3 camPos = camera.positionVec3(); - - // Follow focus nodes movement - dvec3 centerPos = _focusNode->worldPosition(); - dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; - _previousFocusNodePosition = centerPos; - camPos += focusNodeDiff; - - dquat totalRotation = camera.rotationQuaternion(); - dvec3 directionToCenter = normalize(centerPos - camPos); - dvec3 lookUp = camera.lookUpVectorWorldSpace(); - double boundingSphere = _focusNode->boundingSphere(); - dvec3 camDirection = camera.viewDirectionWorldSpace(); - - // Declare other variables used in interaction calculations - double minHeightAboveBoundingSphere = 1; - dvec3 centerToCamera = camPos - centerPos; - dvec3 centerToBoundingSphere; - - // Create the internal representation of the local and global camera rotations - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - directionToCenter, - normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction - dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); - dquat localCameraRotation = inverse(globalCameraRotation) * totalRotation; - - { // Do local roll - glm::dquat cameraRollRotation = - glm::angleAxis(_mouseStates->synchedLocalRollMouseVelocity().x, dvec3(0, 0, 1)); - localCameraRotation = localCameraRotation * cameraRollRotation; - } - if (!_rotateToFocusNodeInterpolator.isInterpolating()) - { // Do local rotation - dvec3 eulerAngles(_mouseStates->synchedLocalRotationMouseVelocity().y, _mouseStates->synchedLocalRotationMouseVelocity().x, 0); - dquat rotationDiff = dquat(eulerAngles); - - localCameraRotation = localCameraRotation * rotationDiff; - } - else - { // Interpolate local rotation to focus node - double t = _rotateToFocusNodeInterpolator.value(); - localCameraRotation = slerp(localCameraRotation, dquat(dvec3(0.0)), t); - _rotateToFocusNodeInterpolator.step(deltaTime * 0.1); // Should probably depend on dt - // This is a fast but ugly solution to slow regaining of control... - if (t > 0.18) { - _rotateToFocusNodeInterpolator.end(); - } - } - { // Do global rotation - dvec2 smoothMouseVelocity = _mouseStates->synchedGlobalRotationMouseVelocity(); - dvec3 eulerAngles(-smoothMouseVelocity.y, -smoothMouseVelocity.x, 0); - dquat rotationDiffCamSpace = dquat(eulerAngles); - - dquat newRotationCamspace = globalCameraRotation * rotationDiffCamSpace; - dquat rotationDiffWorldSpace = newRotationCamspace * inverse(globalCameraRotation); - dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera; - - camPos += rotationDiffVec3; - dvec3 centerToCamera = camPos - centerPos; - directionToCenter = normalize(-centerToCamera); - - dvec3 lookUpWhenFacingCenter = - globalCameraRotation * dvec3(camera.lookUpVectorCameraSpace()); - dmat4 lookAtMat = lookAt( - dvec3(0, 0, 0), - directionToCenter, - lookUpWhenFacingCenter); - globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); - } - { // Move position towards or away from focus node - centerToBoundingSphere = - -directionToCenter * - boundingSphere; - camPos += -(centerToCamera - centerToBoundingSphere) * - _mouseStates->synchedTruckMovementMouseVelocity().y; - } - { // Roll around sphere normal - dquat cameraRollRotation = - angleAxis(_mouseStates->synchedGlobalRollMouseVelocity().x, -directionToCenter); - globalCameraRotation = cameraRollRotation * globalCameraRotation; - } - { // Push up to surface - dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere); - - double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera); - camPos += -directionToCenter * - max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0); - } - - // Update the camera state - camera.setPositionVec3(camPos); - camera.setRotation(globalCameraRotation * localCameraRotation); - } -} - -bool OrbitalInteractionMode::followingNodeRotation() const { - return false; -} - -void OrbitalInteractionMode::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) { - _mouseStates->updateMouseStatesFromInput(inputState, deltaTime); -} - -GlobeBrowsingInteractionMode::GlobeBrowsingInteractionMode(std::shared_ptr mouseStates) - : OrbitalInteractionMode(mouseStates) -{ - -} - -GlobeBrowsingInteractionMode::~GlobeBrowsingInteractionMode() { - -} - -void GlobeBrowsingInteractionMode::setFocusNode(SceneGraphNode* focusNode) { - InteractionMode::setFocusNode(focusNode); - -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - Renderable* baseRenderable = _focusNode->renderable(); - if (globebrowsing::RenderableGlobe* globe = dynamic_cast(baseRenderable)) { - _globe = globe; - } - else { - LWARNING("Focus node is not a renderable globe. GlobeBrowsingInteraction is not possible"); - _globe = nullptr; - } -#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -} - -void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& camera, double deltaTime) { - -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - using namespace glm; - if (_focusNode && _globe) { - // Declare variables to use in interaction calculations - // Shrink interaction ellipsoid to enable interaction below height = 0 - double ellipsoidShrinkTerm = _globe->interactionDepthBelowEllipsoid(); - double minHeightAboveGround = _globe->generalProperties().cameraMinHeight; - - // Read the current state of the camera and focusnode - dvec3 camPos = camera.positionVec3(); - dvec3 centerPos = _focusNode->worldPosition(); - - // Follow focus nodes movement - dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; - _previousFocusNodePosition = centerPos; - camPos += focusNodeDiff; - - dquat totalRotation = camera.rotationQuaternion(); - dvec3 lookUp = camera.lookUpVectorWorldSpace(); - dvec3 camDirection = camera.viewDirectionWorldSpace(); - - // Sampling of height is done in the reference frame of the globe. - // Hence, the camera position needs to be transformed with the inverse model matrix - glm::dmat4 inverseModelTransform = _globe->inverseModelTransform(); - glm::dmat4 modelTransform = _globe->modelTransform(); - glm::dvec3 cameraPositionModelSpace = - glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); - - dvec3 posDiff = camPos - centerPos; - - dvec3 directionFromSurfaceToCameraModelSpace = - _globe->ellipsoid().geodeticSurfaceNormal( - _globe->ellipsoid().cartesianToGeodetic2(cameraPositionModelSpace)); - dvec3 directionFromSurfaceToCamera = - normalize(dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace); - dvec3 centerToEllipsoidSurface = dmat3(modelTransform) * (_globe->projectOnEllipsoid(cameraPositionModelSpace) - - directionFromSurfaceToCameraModelSpace * ellipsoidShrinkTerm); - dvec3 ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface); - - double heightToSurface = - _globe->getHeight(cameraPositionModelSpace) + ellipsoidShrinkTerm; - - double distFromCenterToSurface = - length(centerToEllipsoidSurface); - double distFromEllipsoidSurfaceToCamera = length(ellipsoidSurfaceToCamera); - double distFromCenterToCamera = length(posDiff); - double distFromSurfaceToCamera = - distFromEllipsoidSurfaceToCamera - heightToSurface; - - // Create the internal representation of the local and global camera rotations - dmat4 lookAtMat = lookAt( - dvec3(0.0, 0.0, 0.0), - -directionFromSurfaceToCamera, - normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction - dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat))); - dquat localCameraRotation = inverse(globalCameraRotation) * totalRotation; - - // Rotate with the globe - dmat3 globeStateMatrix = _focusNode->worldRotationMatrix(); - dquat globeRotation = quat_cast(globeStateMatrix); - dquat focusNodeRotationDiff = _previousFocusNodeRotation * inverse(globeRotation); - _previousFocusNodeRotation = globeRotation; - - { // Do local roll - glm::dquat cameraRollRotation = - glm::angleAxis(_mouseStates->synchedLocalRollMouseVelocity().x, dvec3(0, 0, 1)); - localCameraRotation = localCameraRotation * cameraRollRotation; - } - if(!_rotateToFocusNodeInterpolator.isInterpolating()) - { // Do local rotation - glm::dvec3 eulerAngles(_mouseStates->synchedLocalRotationMouseVelocity().y, _mouseStates->synchedLocalRotationMouseVelocity().x, 0); - glm::dquat rotationDiff = glm::dquat(eulerAngles); - - localCameraRotation = localCameraRotation * rotationDiff; - } - else - { // Interpolate local rotation to focus node - double t = _rotateToFocusNodeInterpolator.value(); - localCameraRotation = slerp(localCameraRotation, dquat(dvec3(0.0)), t); - _rotateToFocusNodeInterpolator.step(0.002); // Should probably depend on dt - // This is a fast but ugly solution to slow regaining of control... - if (t > 0.2) { - _rotateToFocusNodeInterpolator.end(); - } - } - { // Do global rotation (horizontal movement) - glm::dvec3 eulerAngles = glm::dvec3( - -_mouseStates->synchedGlobalRotationMouseVelocity().y, - -_mouseStates->synchedGlobalRotationMouseVelocity().x, - 0) * glm::clamp(distFromSurfaceToCamera / distFromCenterToSurface, 0.0, 1.0); - glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles); - - glm::dquat rotationDiffWorldSpace = - globalCameraRotation * - rotationDiffCamSpace * - glm::inverse(globalCameraRotation); - - glm::dvec3 rotationDiffVec3 = - (distFromCenterToCamera * directionFromSurfaceToCamera) - * rotationDiffWorldSpace - - (distFromCenterToCamera * directionFromSurfaceToCamera); - - camPos += rotationDiffVec3; - - posDiff = camPos - centerPos; - glm::dvec3 rotationDiffVec3AroundCenter = - posDiff - * focusNodeRotationDiff - - (posDiff); - camPos += rotationDiffVec3AroundCenter; - - - - - - cameraPositionModelSpace = - glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); - - directionFromSurfaceToCameraModelSpace = - _globe->ellipsoid().geodeticSurfaceNormal( - _globe->ellipsoid().cartesianToGeodetic2(cameraPositionModelSpace)); - directionFromSurfaceToCamera = - normalize(dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace); - centerToEllipsoidSurface = dmat3(modelTransform) * (_globe->projectOnEllipsoid(cameraPositionModelSpace) - - directionFromSurfaceToCameraModelSpace * ellipsoidShrinkTerm); - ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface); - - - glm::dvec3 lookUpWhenFacingSurface = - inverse(focusNodeRotationDiff) * globalCameraRotation * glm::dvec3(camera.lookUpVectorCameraSpace()); - glm::dmat4 lookAtMat = glm::lookAt( - glm::dvec3(0, 0, 0), - -directionFromSurfaceToCamera, - lookUpWhenFacingSurface); - globalCameraRotation = - glm::normalize(glm::quat_cast(glm::inverse(lookAtMat))); - } - { // Move position towards or away from focus node - camPos += -directionFromSurfaceToCamera * distFromSurfaceToCamera * - _mouseStates->synchedTruckMovementMouseVelocity().y; - } - { // Roll around ellipsoid normal - glm::dquat cameraRollRotation = - glm::angleAxis(_mouseStates->synchedGlobalRollMouseVelocity().x, directionFromSurfaceToCamera); - globalCameraRotation = cameraRollRotation * globalCameraRotation; - } - { // Push up to surface - ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface); - - // Sampling of height is done in the reference frame of the globe. - // Hence, the camera position needs to be transformed with the inverse model matrix - glm::dmat4 inverseModelTransform = _globe->inverseModelTransform(); - glm::dvec3 cameraPositionModelSpace = - glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); - - distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera); - double heightToSurface = - _globe->getHeight(cameraPositionModelSpace) + ellipsoidShrinkTerm; - double heightToSurfaceAndPadding = heightToSurface + minHeightAboveGround; - camPos += directionFromSurfaceToCamera * - glm::max(heightToSurfaceAndPadding - distFromEllipsoidSurfaceToCamera, 0.0); - } - - // Update the camera state - camera.setPositionVec3(camPos); - camera.setRotation(globalCameraRotation * localCameraRotation); - } -#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -} - -bool GlobeBrowsingInteractionMode::followingNodeRotation() const { - return true; -} - -#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED -void GlobeBrowsingInteractionMode::goToChunk(Camera& camera, - globebrowsing::TileIndex ti, glm::vec2 uv, bool resetCameraDirection) { - using namespace globebrowsing; - - // Camera position in model space - glm::dvec3 camPos = camera.positionVec3(); - glm::dmat4 inverseModelTransform = _globe->inverseModelTransform(); - glm::dvec3 cameraPositionModelSpace = - glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); - - GeodeticPatch patch(ti); - Geodetic2 corner = patch.getCorner(SOUTH_WEST); - Geodetic2 positionOnPatch = patch.getSize(); - positionOnPatch.lat *= uv.y; - positionOnPatch.lon *= uv.x; - Geodetic2 pointPosition = corner + positionOnPatch; - - glm::dvec3 positionOnEllipsoid = - _globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace); - double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); - - goToGeodetic3(camera, {pointPosition, altitude}); - - if (resetCameraDirection) { - this->resetCameraDirection(camera, pointPosition); - } -} - -void GlobeBrowsingInteractionMode::goToGeodetic2(Camera& camera, - globebrowsing::Geodetic2 geo2, bool resetCameraDirection) { - using namespace globebrowsing; - - // Camera position in model space - glm::dvec3 camPos = camera.positionVec3(); - glm::dmat4 inverseModelTransform = _globe->inverseModelTransform(); - glm::dvec3 cameraPositionModelSpace = - glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1)); - - glm::dvec3 positionOnEllipsoid = - _globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace); - double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid); - - goToGeodetic3(camera, {geo2, altitude}); - - if (resetCameraDirection) { - this->resetCameraDirection(camera, geo2); - } -} - -void GlobeBrowsingInteractionMode::goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3) { - glm::dvec3 positionModelSpace = _globe->ellipsoid().cartesianPosition(geo3); - glm::dmat4 modelTransform = _globe->modelTransform(); - glm::dvec3 positionWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0); - camera.setPositionVec3(positionWorldSpace); -} - - void GlobeBrowsingInteractionMode::resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2) { - using namespace globebrowsing; - - // Camera is described in world space - glm::dmat4 modelTransform = _globe->modelTransform(); - - // Lookup vector - glm::dvec3 positionModelSpace = _globe->ellipsoid().cartesianSurfacePosition(geo2); - glm::dvec3 slightlyNorth = _globe->ellipsoid().cartesianSurfacePosition( - Geodetic2(geo2.lat + 0.001, geo2.lon)); - glm::dvec3 lookUpModelSpace = glm::normalize(slightlyNorth - positionModelSpace); - glm::dvec3 lookUpWorldSpace = glm::dmat3(modelTransform) * lookUpModelSpace; - - // Lookat vector - glm::dvec3 lookAtWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0); - - // Eye position - glm::dvec3 eye = camera.positionVec3(); - - // Matrix - glm::dmat4 lookAtMatrix = glm::lookAt( - eye, lookAtWorldSpace, lookUpWorldSpace); - - // Set rotation - glm::dquat rotation = glm::quat_cast(inverse(lookAtMatrix)); - camera.setRotation(rotation); - } - -#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED - -} // namespace interaction -} // namespace openspace diff --git a/src/interaction/keybindingmanager.cpp b/src/interaction/keybindingmanager.cpp new file mode 100644 index 0000000000..2f3db8e2bc --- /dev/null +++ b/src/interaction/keybindingmanager.cpp @@ -0,0 +1,178 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace { + const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/main.hbs"; + const char* KeybindingTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/keybinding.hbs"; + const char* JsFilename = "${OPENSPACE_DATA}/web/keybindings/script.js"; +} // namespace + +#include "keybindingmanager_lua.inl" + +namespace openspace { +namespace interaction { + +KeyBindingManager::KeyBindingManager() + : DocumentationGenerator( + "Documentation", + "keybindings", + { + { "keybindingTemplate", KeybindingTemplateFilename }, + { "mainTemplate", MainTemplateFilename } + }, + JsFilename + ) +{ } + +void KeyBindingManager::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { + if (action == KeyAction::Press || action == KeyAction::Repeat) { + // iterate over key bindings + std::pair::iterator, + std::multimap::iterator> ret = + _keyLua.equal_range({ key, modifier }); + for (std::multimap::iterator it = ret.first; + it != ret.second; + ++it) + { + scripting::ScriptEngine::RemoteScripting remote = + it->second.synchronization ? + scripting::ScriptEngine::RemoteScripting::Yes : + scripting::ScriptEngine::RemoteScripting::No; + + OsEng.scriptEngine().queueScript(it->second.command, remote); + } + } +} + +void KeyBindingManager::resetKeyBindings() { + _keyLua.clear(); +} + +void KeyBindingManager::bindKeyLocal(Key key, KeyModifier modifier, + std::string luaCommand, std::string documentation) +{ + _keyLua.insert({ + { key, modifier }, + { + std::move(luaCommand), + Synchronized::No, + std::move(documentation) + } + }); +} + +void KeyBindingManager::bindKey(Key key, KeyModifier modifier, + std::string luaCommand, std::string documentation) +{ + _keyLua.insert({ + { key, modifier }, + { + std::move(luaCommand), + Synchronized::Yes, + std::move(documentation) + } + }); +} + +std::string KeyBindingManager::generateJson() const { + std::stringstream json; + json << "["; + bool first = true; + for (const std::pair& p : _keyLua) { + if (!first) { + json << ","; + } + first = false; + json << "{"; + json << "\"key\": \"" << std::to_string(p.first) << "\","; + json << "\"script\": \"" << p.second.command << "\","; + json << "\"remoteScripting\": " << (p.second.synchronization ? "true," : "false,"); + json << "\"documentation\": \"" << p.second.documentation << "\""; + json << "}"; + } + json << "]"; + + std::string jsonString = ""; + for (const char& c : json.str()) { + if (c == '\'') { + jsonString += "\\'"; + } else { + jsonString += c; + } + } + + return jsonString; +} + +scripting::LuaLibrary KeyBindingManager::luaLibrary() { + return { + "", + { + { + "clearKeys", + &luascriptfunctions::clearKeys, + "", + "Clear all key bindings" + }, + { + "bindKey", + &luascriptfunctions::bindKey, + "string, string [,string]", + "Binds a key by name to a lua string command to execute both locally " + "and to broadcast to clients if this is the host of a parallel session. " + "The first argument is the key, the second argument is the Lua command " + "that is to be executed, and the optional third argument is a human " + "readable description of the command for documentation purposes." + }, + { + "bindKeyLocal", + &luascriptfunctions::bindKeyLocal, + "string, string [,string]", + "Binds a key by name to a lua string command to execute only locally. " + "The first argument is the key, the second argument is the Lua command " + "that is to be executed, and the optional third argument is a human " + "readable description of the command for documentation purposes." + }, + } + }; +} + +} // namespace interaction +} // namespace openspace diff --git a/src/interaction/interactionhandler_lua.inl b/src/interaction/keybindingmanager_lua.inl similarity index 61% rename from src/interaction/interactionhandler_lua.inl rename to src/interaction/keybindingmanager_lua.inl index 34b2db6312..ba6b75e423 100644 --- a/src/interaction/interactionhandler_lua.inl +++ b/src/interaction/keybindingmanager_lua.inl @@ -25,38 +25,6 @@ namespace openspace { namespace luascriptfunctions { -/** - * \ingroup LuaScripts - * setOrigin(): - * Set the origin of the camera - */ -int setOrigin(lua_State* L) { - using ghoul::lua::luaTypeToString; - - int nArguments = lua_gettop(L); - if (nArguments != 1) - return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); - - const int type = lua_type(L, -1); - if (type != LUA_TSTRING) - return luaL_error(L, "Expected string, got %i", type); - - std::string s = luaL_checkstring(L, -1); - - SceneGraphNode* node = sceneGraphNode(s); - if (!node) { - LWARNINGC( - "lua.setOrigin", - "Could not find a node in scenegraph called '" << s << "'" - ); - return 0; - } - - OsEng.interactionHandler().setFocusNode(node); - - return 0; -} - /** * \ingroup LuaScripts * bindKey(): @@ -95,7 +63,7 @@ int bindKey(lua_State* L) { documentation = luaL_checkstring(L, DocumentationLocation); } - OsEng.interactionHandler().bindKey( + OsEng.keyBindingManager().bindKey( iKey.key, iKey.modifier, std::move(command), @@ -141,7 +109,7 @@ int bindKeyLocal(lua_State* L) { documentation = luaL_checkstring(L, DocumentationLocation); } - OsEng.interactionHandler().bindKeyLocal( + OsEng.keyBindingManager().bindKeyLocal( iKey.key, iKey.modifier, std::move(command), @@ -151,7 +119,6 @@ int bindKeyLocal(lua_State* L) { return 0; } - /** * \ingroup LuaScripts * clearKeys(): @@ -164,89 +131,11 @@ int clearKeys(lua_State* L) { if (nArguments != 0) return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments); - OsEng.interactionHandler().resetKeyBindings(); + OsEng.keyBindingManager().resetKeyBindings(); return 0; } -int goToChunk(lua_State* L) { - using ghoul::lua::luaTypeToString; - - int nArguments = lua_gettop(L); - if (nArguments != 3) - return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments); - - int x = static_cast(lua_tonumber(L, 1)); - int y = static_cast(lua_tonumber(L, 2)); - int level = static_cast(lua_tonumber(L, 3)); - - OsEng.interactionHandler().goToChunk(x, y, level); - - return 0; -} - -int goToGeo(lua_State* L) { - using ghoul::lua::luaTypeToString; - - int nArguments = lua_gettop(L); - if (nArguments != 2) - return luaL_error(L, "Expected %i arguments, got %i", 2, nArguments); - - double latitude = static_cast(lua_tonumber(L, 1)); - double longitude = static_cast(lua_tonumber(L, 2)); - - OsEng.interactionHandler().goToGeo(latitude, longitude); - - return 0; -} - -int restoreCameraStateFromFile(lua_State* L) { - using ghoul::lua::luaTypeToString; - - int nArguments = lua_gettop(L); - if (nArguments != 1) - return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); - - std::string cameraStateFilePath = luaL_checkstring(L, -1); - - if (cameraStateFilePath.empty()) { - return luaL_error(L, "filepath string is empty"); - } - - OsEng.interactionHandler().restoreCameraStateFromFile(cameraStateFilePath); - return 0; -} - -int saveCameraStateToFile(lua_State* L) { - using ghoul::lua::luaTypeToString; - - int nArguments = lua_gettop(L); - if (nArguments != 1) - return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); - - std::string cameraStateFilePath = luaL_checkstring(L, -1); - - if (cameraStateFilePath.empty()) { - return luaL_error(L, "filepath string is empty"); - } - - OsEng.interactionHandler().saveCameraStateToFile(cameraStateFilePath); - return 0; -} - -int resetCameraDirection(lua_State* L) { - using ghoul::lua::luaTypeToString; - - int nArguments = lua_gettop(L); - if (nArguments != 0) { - return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments); - } - - OsEng.interactionHandler().resetCameraDirection(); - return 0; -} - - } // namespace luascriptfunctions } // namespace openspace diff --git a/src/interaction/keyframenavigator.cpp b/src/interaction/keyframenavigator.cpp new file mode 100644 index 0000000000..1ce1773e2f --- /dev/null +++ b/src/interaction/keyframenavigator.cpp @@ -0,0 +1,127 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +namespace openspace { +namespace interaction { + +void KeyframeNavigator::updateCamera(Camera& camera) { + double now = OsEng.runTime(); + + if (_cameraPoseTimeline.nKeyframes() == 0) { + return; + } + + const Keyframe* nextKeyframe = _cameraPoseTimeline.firstKeyframeAfter(now); + const Keyframe* prevKeyframe = _cameraPoseTimeline.lastKeyframeBefore(now); + double nextTime = 0; + double prevTime = 0; + double t = 0; + + if (nextKeyframe) { + nextTime = nextKeyframe->timestamp; + } else { + return; + } + + if (prevKeyframe) { + prevTime = prevKeyframe->timestamp; + t = (now - prevTime) / (nextTime - prevTime); + } else { + // If there is no keyframe before: Only use the next keyframe. + prevTime = nextTime; + prevKeyframe = nextKeyframe; + t = 1; + } + + _cameraPoseTimeline.removeKeyframesBefore(prevTime); + + const CameraPose& prevPose = prevKeyframe->data; + const CameraPose& nextPose = nextKeyframe->data; + + Scene* scene = camera.parent()->scene(); + SceneGraphNode* prevFocusNode = scene->sceneGraphNode(prevPose.focusNode); + SceneGraphNode* nextFocusNode = scene->sceneGraphNode(nextPose.focusNode); + + if (!prevFocusNode || !nextFocusNode) { + return; + } + + glm::dvec3 prevKeyframeCameraPosition = prevPose.position; + glm::dvec3 nextKeyframeCameraPosition = nextPose.position; + glm::dquat prevKeyframeCameraRotation = prevPose.rotation; + glm::dquat nextKeyframeCameraRotation = nextPose.rotation; + + // Transform position and rotation based on focus node rotation (if following rotation) + if (prevPose.followFocusNodeRotation) { + prevKeyframeCameraRotation = prevFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(prevPose.rotation)); + prevKeyframeCameraPosition = prevFocusNode->worldRotationMatrix() * prevPose.position; + } + if (nextPose.followFocusNodeRotation) { + nextKeyframeCameraRotation = nextFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(nextPose.rotation)); + nextKeyframeCameraPosition = nextFocusNode->worldRotationMatrix() * nextPose.position; + } + + // Transform position based on focus node position + prevKeyframeCameraPosition += prevFocusNode->worldPosition(); + nextKeyframeCameraPosition += nextFocusNode->worldPosition(); + + // Linear interpolation + camera.setPositionVec3(prevKeyframeCameraPosition * (1 - t) + nextKeyframeCameraPosition * t); + camera.setRotation(glm::slerp(prevKeyframeCameraRotation, nextKeyframeCameraRotation, t)); +} + +Timeline& KeyframeNavigator::timeline() { + return _cameraPoseTimeline; +} + +void KeyframeNavigator::addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose) { + timeline().addKeyframe(timestamp, pose); +} + +void KeyframeNavigator::removeKeyframesAfter(double timestamp) { + timeline().removeKeyframesAfter(timestamp); +} + +void KeyframeNavigator::clearKeyframes() { + timeline().clearKeyframes(); +} + +size_t KeyframeNavigator::nKeyframes() const { + return _cameraPoseTimeline.nKeyframes(); +} + +} // namespace interaction +} // namespace openspace diff --git a/src/interaction/mousestate.cpp b/src/interaction/mousestate.cpp new file mode 100644 index 0000000000..f6e61e9371 --- /dev/null +++ b/src/interaction/mousestate.cpp @@ -0,0 +1,177 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +namespace openspace { +namespace interaction { + +MouseState::MouseState(double scaleFactor) + : velocity(scaleFactor, 1) + , previousPosition(0.0, 0.0) +{ } + +void MouseState::setFriction(double friction) { + velocity.setFriction(friction); +} + +void MouseState::setVelocityScaleFactor(double scaleFactor) { + velocity.setScaleFactor(scaleFactor); +} + +MouseStates::MouseStates(double sensitivity, double velocityScaleFactor) + : _sensitivity(sensitivity) + , _globalRotationMouseState(velocityScaleFactor) + , _localRotationMouseState(velocityScaleFactor) + , _truckMovementMouseState(velocityScaleFactor) + , _localRollMouseState(velocityScaleFactor) + , _globalRollMouseState(velocityScaleFactor) +{ } + +void MouseStates::updateMouseStatesFromInput(const InputState& inputState, + double deltaTime) +{ + glm::dvec2 mousePosition = inputState.getMousePosition(); + + bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1); + bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2); + bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3); + bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl); + bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift); + + // Update the mouse states + if (button1Pressed && !keyShiftPressed) { + if (keyCtrlPressed) { + glm::dvec2 mousePositionDelta = + _localRotationMouseState.previousPosition - mousePosition; + _localRotationMouseState.velocity.set( + mousePositionDelta * _sensitivity, deltaTime); + + _globalRotationMouseState.previousPosition = mousePosition; + _globalRotationMouseState.velocity.decelerate(deltaTime); + } + else { + glm::dvec2 mousePositionDelta = + _globalRotationMouseState.previousPosition - mousePosition; + _globalRotationMouseState.velocity.set( + mousePositionDelta * _sensitivity, deltaTime); + + _localRotationMouseState.previousPosition = mousePosition; + _localRotationMouseState.velocity.decelerate(deltaTime); + } + } + else { // !button1Pressed + _localRotationMouseState.previousPosition = mousePosition; + _localRotationMouseState.velocity.decelerate(deltaTime); + + _globalRotationMouseState.previousPosition = mousePosition; + _globalRotationMouseState.velocity.decelerate(deltaTime); + } + if (button2Pressed) { + glm::dvec2 mousePositionDelta = + _truckMovementMouseState.previousPosition - mousePosition; + _truckMovementMouseState.velocity.set( + mousePositionDelta * _sensitivity, deltaTime); + } + else { // !button2Pressed + _truckMovementMouseState.previousPosition = mousePosition; + _truckMovementMouseState.velocity.decelerate(deltaTime); + } + if (button3Pressed || (keyShiftPressed && button1Pressed)) { + if (keyCtrlPressed) { + glm::dvec2 mousePositionDelta = + _localRollMouseState.previousPosition - mousePosition; + _localRollMouseState.velocity.set( + mousePositionDelta * _sensitivity, deltaTime); + + _globalRollMouseState.previousPosition = mousePosition; + _globalRollMouseState.velocity.decelerate(deltaTime); + } + else { + glm::dvec2 mousePositionDelta = + _globalRollMouseState.previousPosition - mousePosition; + _globalRollMouseState.velocity.set( + mousePositionDelta * _sensitivity, deltaTime); + + _localRollMouseState.previousPosition = mousePosition; + _localRollMouseState.velocity.decelerate(deltaTime); + } + } + else { // !button3Pressed + _globalRollMouseState.previousPosition = mousePosition; + _globalRollMouseState.velocity.decelerate(deltaTime); + + _localRollMouseState.previousPosition = mousePosition; + _localRollMouseState.velocity.decelerate(deltaTime); + } +} + +void MouseStates::setRotationalFriction(double friction) { + _localRotationMouseState.setFriction(friction); + _localRollMouseState.setFriction(friction); + _globalRollMouseState.setFriction(friction); +} + +void MouseStates::setHorizontalFriction(double friction) { + _globalRotationMouseState.setFriction(friction); +} + +void MouseStates::setVerticalFriction(double friction) { + _truckMovementMouseState.setFriction(friction); +} + +void MouseStates::setSensitivity(double sensitivity) { + _sensitivity = sensitivity; +} + +void MouseStates::setVelocityScaleFactor(double scaleFactor) { + _globalRotationMouseState.setVelocityScaleFactor(scaleFactor); + _localRotationMouseState.setVelocityScaleFactor(scaleFactor); + _truckMovementMouseState.setVelocityScaleFactor(scaleFactor); + _localRollMouseState.setVelocityScaleFactor(scaleFactor); + _globalRollMouseState.setVelocityScaleFactor(scaleFactor); +} + +glm::dvec2 MouseStates::globalRotationMouseVelocity() const{ + return _globalRotationMouseState.velocity.get(); +} + +glm::dvec2 MouseStates::localRotationMouseVelocity() const{ + return _localRotationMouseState.velocity.get(); +} + +glm::dvec2 MouseStates::truckMovementMouseVelocity() const{ + return _truckMovementMouseState.velocity.get(); +} + +glm::dvec2 MouseStates::localRollMouseVelocity() const{ + return _localRollMouseState.velocity.get(); +} + +glm::dvec2 MouseStates::globalRollMouseVelocity() const{ + return _globalRollMouseState.velocity.get(); +} + +} // namespace interaction +} // namespace openspace diff --git a/src/interaction/navigationhandler.cpp b/src/interaction/navigationhandler.cpp new file mode 100644 index 0000000000..43218accc1 --- /dev/null +++ b/src/interaction/navigationhandler.cpp @@ -0,0 +1,299 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace { + const char* _loggerCat = "NavigationHandler"; + + const char* KeyFocus = "Focus"; + const char* KeyPosition = "Position"; + const char* KeyRotation = "Rotation"; +} // namespace + +#include "navigationhandler_lua.inl" + +namespace openspace { +namespace interaction { + +NavigationHandler::NavigationHandler() + : properties::PropertyOwner("NavigationHandler") + , _origin("origin", "Origin", "") + , _useKeyFrameInteraction("useKeyFrameInteraction", "Use keyframe interaction", false) +{ + _origin.onChange([this]() { + SceneGraphNode* node = sceneGraphNode(_origin.value()); + if (!node) { + LWARNING("Could not find a node in scenegraph called '" << _origin.value() << "'"); + return; + } + setFocusNode(node); + resetCameraDirection(); + }); + + _inputState = std::make_unique(); + _orbitalNavigator = std::make_unique(); + _keyframeNavigator = std::make_unique(); + + // Add the properties + addProperty(_origin); + addProperty(_useKeyFrameInteraction); + addPropertySubOwner(*_orbitalNavigator); +} + +NavigationHandler::~NavigationHandler() +{ } + +void NavigationHandler::initialize() { + OsEng.parallelConnection().connectionEvent()->subscribe("NavigationHandler", "statusChanged", [this]() { + if (OsEng.parallelConnection().status() == ParallelConnection::Status::ClientWithHost) { + _useKeyFrameInteraction = true; + } + }); +} + +void NavigationHandler::deinitialize() { + OsEng.parallelConnection().connectionEvent()->unsubscribe("NavigationHandler"); +} + +void NavigationHandler::setFocusNode(SceneGraphNode* node) { + _orbitalNavigator->setFocusNode(node); + _camera->setFocusPositionVec3(focusNode()->worldPosition()); +} + +void NavigationHandler::setCamera(Camera* camera) { + _camera = camera; + //setFocusNode(_camera->parent()); +} + +void NavigationHandler::resetCameraDirection() { + LINFO("Setting camera direction to point at focus node."); + _orbitalNavigator->startInterpolateCameraDirection(*_camera); +} + +const OrbitalNavigator& NavigationHandler::orbitalNavigator() const { + return *_orbitalNavigator; +} + +KeyframeNavigator& NavigationHandler::keyframeNavigator() const { + return *_keyframeNavigator; +} + +void NavigationHandler::updateCamera(double deltaTime) { + ghoul_assert(_inputState != nullptr, "InputState cannot be null!"); + ghoul_assert(_camera != nullptr, "Camera cannot be null!"); + + if (_cameraUpdatedFromScript) { + _cameraUpdatedFromScript = false; + } + else { + if (_camera && focusNode()) { + if (_useKeyFrameInteraction) { + _keyframeNavigator->updateCamera(*_camera); + } + else { + _orbitalNavigator->updateMouseStatesFromInput(*_inputState, deltaTime); + _orbitalNavigator->updateCameraStateFromMouseStates(*_camera, deltaTime); + } + _camera->setFocusPositionVec3(focusNode()->worldPosition()); + } + } +} + +SceneGraphNode* NavigationHandler::focusNode() const { + return _orbitalNavigator->focusNode(); +} + +glm::dvec3 NavigationHandler::focusNodeToCameraVector() const { + return _camera->positionVec3() - focusNode()->worldPosition(); +} + +glm::quat NavigationHandler::focusNodeToCameraRotation() const { + glm::dmat4 invWorldRotation = glm::inverse(focusNode()->worldRotationMatrix()); + return glm::quat(invWorldRotation) * glm::quat(_camera->rotationQuaternion()); +} + +Camera* NavigationHandler::camera() const { + return _camera; +} + +const InputState& NavigationHandler::inputState() const { + return *_inputState; +} + +void NavigationHandler::mouseButtonCallback(MouseButton button, MouseAction action) { + _inputState->mouseButtonCallback(button, action); +} + +void NavigationHandler::mousePositionCallback(double x, double y) { + _inputState->mousePositionCallback(x, y); +} + +void NavigationHandler::mouseScrollWheelCallback(double pos) { + _inputState->mouseScrollWheelCallback(pos); +} + +void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) { + _inputState->keyboardCallback(key, modifier, action); +} + +void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict) { + bool readSuccessful = true; + + std::string focus; + glm::dvec3 cameraPosition; + glm::dvec4 cameraRotation; // Need to read the quaternion as a vector first. + + readSuccessful &= cameraDict.getValue(KeyFocus, focus); + readSuccessful &= cameraDict.getValue(KeyPosition, cameraPosition); + readSuccessful &= cameraDict.getValue(KeyRotation, cameraRotation); + + if (!readSuccessful) { + throw ghoul::RuntimeError( + "Position, Rotation and Focus need to be defined for camera dictionary."); + } + + SceneGraphNode* node = sceneGraphNode(focus); + if (!node) { + throw ghoul::RuntimeError( + "Could not find a node in scenegraph called '" + focus + "'"); + } + + // Set state + setFocusNode(node); + _camera->setPositionVec3(cameraPosition); + _camera->setRotation(glm::dquat( + cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w)); +} + +ghoul::Dictionary NavigationHandler::getCameraStateDictionary() { + glm::dvec3 cameraPosition; + glm::dquat quat; + glm::dvec4 cameraRotation; + + cameraPosition = _camera->positionVec3(); + quat = _camera->rotationQuaternion(); + cameraRotation = glm::dvec4(quat.w, quat.x, quat.y, quat.z); + + ghoul::Dictionary cameraDict; + cameraDict.setValue(KeyPosition, cameraPosition); + cameraDict.setValue(KeyRotation, cameraRotation); + cameraDict.setValue(KeyFocus, focusNode()->name()); + + return cameraDict; +} + +void NavigationHandler::saveCameraStateToFile(const std::string& filepath) { + if (!filepath.empty()) { + std::string fullpath = absPath(filepath); + LINFO("Saving camera position: " << filepath); + + ghoul::Dictionary cameraDict = getCameraStateDictionary(); + + // TODO : Should get the camera state as a dictionary and save the dictionary to + // a file in form of a lua state and not use ofstreams here. + + std::ofstream ofs(fullpath.c_str()); + + glm::dvec3 p = _camera->positionVec3(); + glm::dquat q = _camera->rotationQuaternion(); + + ofs << "return {" << std::endl; + ofs << " " << KeyFocus << " = " << "\"" << focusNode()->name() << "\"" << "," << std::endl; + ofs << " " << KeyPosition << " = {" + << std::to_string(p.x) << ", " + << std::to_string(p.y) << ", " + << std::to_string(p.z) << "}," << std::endl; + ofs << " " << KeyRotation << " = {" + << std::to_string(q.w) << ", " + << std::to_string(q.x) << ", " + << std::to_string(q.y) << ", " + << std::to_string(q.z) << "}," << std::endl; + ofs << "}"<< std::endl; + + ofs.close(); + } +} + +void NavigationHandler::restoreCameraStateFromFile(const std::string& filepath) { + LINFO("Reading camera state from file: " << filepath); + if (!FileSys.fileExists(filepath)) + throw ghoul::FileNotFoundError(filepath, "CameraFilePath"); + + ghoul::Dictionary cameraDict; + try { + ghoul::lua::loadDictionaryFromFile(filepath, cameraDict); + setCameraStateFromDictionary(cameraDict); + _cameraUpdatedFromScript = true; + } + catch (ghoul::RuntimeError& e) { + LWARNING("Unable to set camera position"); + LWARNING(e.message); + } +} + +scripting::LuaLibrary NavigationHandler::luaLibrary() { + return { + "navigation", + { + { + "saveCameraStateToFile", + &luascriptfunctions::saveCameraStateToFile, + "string", + "Save the current camera state to file" + }, + { + "restoreCameraStateFromFile", + &luascriptfunctions::restoreCameraStateFromFile, + "string", + "Restore the camera state from file" + }, + { + "resetCameraDirection", + &luascriptfunctions::resetCameraDirection, + "void", + "Reset the camera direction to point at the focus node" + } + } + }; +} + +} // namespace interaction +} // namespace openspace diff --git a/src/interaction/navigationhandler_lua.inl b/src/interaction/navigationhandler_lua.inl new file mode 100644 index 0000000000..64d9bf1a21 --- /dev/null +++ b/src/interaction/navigationhandler_lua.inl @@ -0,0 +1,113 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +namespace openspace { + +namespace luascriptfunctions { +/** + * \ingroup LuaScripts + * setOrigin(): + * Set the origin of the camera + */ +int setOrigin(lua_State* L) { + using ghoul::lua::luaTypeToString; + + int nArguments = lua_gettop(L); + if (nArguments != 1) { + return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); + } + + const int type = lua_type(L, -1); + if (type != LUA_TSTRING) { + return luaL_error(L, "Expected string, got %i", type); + } + + std::string s = luaL_checkstring(L, -1); + + SceneGraphNode* node = sceneGraphNode(s); + if (!node) { + LWARNINGC( + "lua.setOrigin", + "Could not find a node in scenegraph called '" << s << "'" + ); + return 0; + } + + OsEng.navigationHandler().setFocusNode(node); + + return 0; +} + +int restoreCameraStateFromFile(lua_State* L) { + using ghoul::lua::luaTypeToString; + + int nArguments = lua_gettop(L); + if (nArguments != 1) { + return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); + } + + std::string cameraStateFilePath = luaL_checkstring(L, -1); + + if (cameraStateFilePath.empty()) { + return luaL_error(L, "filepath string is empty"); + } + + OsEng.navigationHandler().restoreCameraStateFromFile(cameraStateFilePath); + return 0; +} + +int saveCameraStateToFile(lua_State* L) { + using ghoul::lua::luaTypeToString; + + int nArguments = lua_gettop(L); + if (nArguments != 1) { + return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); + } + + std::string cameraStateFilePath = luaL_checkstring(L, -1); + + if (cameraStateFilePath.empty()) { + return luaL_error(L, "filepath string is empty"); + } + + OsEng.navigationHandler().saveCameraStateToFile(cameraStateFilePath); + return 0; +} + +int resetCameraDirection(lua_State* L) { + using ghoul::lua::luaTypeToString; + + int nArguments = lua_gettop(L); + if (nArguments != 0) { + return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments); + } + + OsEng.navigationHandler().resetCameraDirection(); + return 0; +} + + +} // namespace luascriptfunctions + +} // namespace openspace diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp new file mode 100644 index 0000000000..4bbebd12c6 --- /dev/null +++ b/src/interaction/orbitalnavigator.cpp @@ -0,0 +1,532 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2017 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace { + const char* _loggerCat = "OrbitalNavigator"; +} + +namespace openspace { +namespace interaction { + +OrbitalNavigator::OrbitalNavigator() + : properties::PropertyOwner("OrbitalNavigator") + , _rotationalFriction("rotationalFriction", "Rotational friction", true) + , _horizontalFriction("horizontalFriction", "Horizontal friction", true) + , _verticalFriction("verticalFriction", "Vertical friction", true) + , _followFocusNodeRotationDistance("followFocusNodeRotationDistance", + "Follow focus node rotation distance", 2.0f, 0.0f, 10.f) + , _minimumAllowedDistance("minimumAllowedDistance", + "Minimum allowed distance", 10.0f, 0.0f, 10000.f) + , _sensitivity("sensitivity", "Sensitivity", 20.0f, 1.0f, 50.f) + , _motionLag("motionLag", "Motion lag", 0.5f, 0.f, 1.f) + , _mouseStates(_sensitivity * pow(10.0,-4), 1 / (_motionLag + 0.0000001)) +{ + auto smoothStep = + [](double t) { + double res = 3.0 * t*t - 2.0 * t*t*t; + return glm::clamp(res, 0.0, 1.0); + }; + _followRotationInterpolator.setTransferFunction(smoothStep); + + // The transfer function is used here to get a different interpolation than the one + // obtained from newValue = lerp(0, currentValue, dt). That one will result in an + // exponentially decreasing value but we want to be able to control it. Either as + // a linear interpolation or a smooth step interpolation. Therefore we use + // newValue = lerp(0, currentValue * f(t) * dt) where f(t) is the transfer function + // and lerp is a linear iterpolation + // lerp(endValue, startValue, interpolationParameter). + // + // The transfer functions are derived from: + // f(t) = d/dt ( ln(1 / f_orig(t)) ) where f_orig is the transfer function that would + // be used if the interpolation was sinply linear between a start value and an end + // value instead of current value and end value (0) as we use it when inerpoláting. + // As an example f_orig(t) = 1 - t yields f(t) = 1 / (1 - t) which results in a linear + // interpolation from 1 to 0. + + auto smoothStepDerivedTranferFunction = + [](double t) { + return (6 * (t + t*t) / (1 - 3 * t*t + 2 * t*t*t)); + }; + _rotateToFocusNodeInterpolator.setTransferFunction(smoothStepDerivedTranferFunction); + + // Define callback functions for changed properties + _rotationalFriction.onChange([&]() { + _mouseStates.setRotationalFriction(_rotationalFriction); + }); + _horizontalFriction.onChange([&]() { + _mouseStates.setHorizontalFriction(_horizontalFriction); + }); + _verticalFriction.onChange([&]() { + _mouseStates.setVerticalFriction(_verticalFriction); + }); + _sensitivity.onChange([&]() { + _mouseStates.setSensitivity(_sensitivity * pow(10.0,-4)); + }); + _motionLag.onChange([&]() { + _mouseStates.setVelocityScaleFactor(1 / (_motionLag + 0.0000001)); + }); + + // Add the properties + addProperty(_rotationalFriction); + addProperty(_horizontalFriction); + addProperty(_verticalFriction); + addProperty(_followFocusNodeRotationDistance); + addProperty(_minimumAllowedDistance); + addProperty(_sensitivity); + addProperty(_motionLag); +} + +OrbitalNavigator::~OrbitalNavigator() +{ } + +void OrbitalNavigator::updateMouseStatesFromInput(const InputState& inputState, + double deltaTime) +{ + _mouseStates.updateMouseStatesFromInput(inputState, deltaTime); +} + +void OrbitalNavigator::updateCameraStateFromMouseStates(Camera& camera, + double deltaTime) +{ + if (_focusNode) { + // Read the current state of the camera + glm::dvec3 camPos = camera.positionVec3(); + glm::dvec3 centerPos = _focusNode->worldPosition(); + + // Follow focus nodes movement + glm::dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition; + _previousFocusNodePosition = centerPos; + camPos += focusNodeDiff; + + // Calculate a position handle based on the camera position in world space + SurfacePositionHandle posHandle = calculateSurfacePositionHandle(camPos); + + // Decompose camera rotation so that we can handle global and local rotation + // individually. Then we combine them again when finished. + CameraRotationDecomposition camRot = decomposeCameraRotation( + camPos, + camera.rotationQuaternion(), + camera.lookUpVectorWorldSpace(), + camera.viewDirectionWorldSpace() + ); + + // Rotate with the object by finding a differential rotation from the previous + // to the current rotation + glm::dmat3 objectStateMatrix = _focusNode->worldRotationMatrix(); + glm::dquat objectRotation = glm::quat_cast(objectStateMatrix); + glm::dquat focusNodeRotationDiff = + _previousFocusNodeRotation * glm::inverse(objectRotation); + _previousFocusNodeRotation = objectRotation; + + // Interpolate rotation differential so that the camera rotates with the object + // only if close enough + focusNodeRotationDiff = interpolateRotationDifferential( + deltaTime, + 1.0, + focusNodeRotationDiff, + centerPos, + camPos, + posHandle + ); + + // Update local rotation + camRot.localRotation = roll(deltaTime, camRot.localRotation); + camRot.localRotation = interpolateLocalRotation(deltaTime, camRot.localRotation); + camRot.localRotation = rotateLocally(deltaTime, camRot.localRotation); + + // Horizontal translation + camPos = translateHorizontally( + deltaTime, + camPos, + centerPos, + focusNodeRotationDiff, + camRot.globalRotation, + posHandle + ); + + // Horizontal translation by focus node rotation + camPos = followFocusNodeRotation( + camPos, + centerPos, + focusNodeRotationDiff + ); + + // Recalculate posHandle since horizontal position changed + posHandle = calculateSurfacePositionHandle(camPos); + + camRot.globalRotation = rotateGlobally( + camRot.globalRotation, + centerPos, + focusNodeRotationDiff, + camPos, + posHandle + ); + + // Rotate around the surface out direction + camRot.globalRotation = rotateHorizontally( + deltaTime, + camRot.globalRotation, + camPos, + posHandle + ); + + // Perform the vertical movements + camPos = translateVertically(deltaTime, camPos, centerPos, posHandle); + camPos = pushToSurface( + _minimumAllowedDistance, + camPos, + centerPos, + posHandle + ); + + // Update the camera state + camera.setPositionVec3(camPos); + camera.setRotation(camRot.globalRotation * camRot.localRotation); + } +} + +void OrbitalNavigator::setFocusNode(SceneGraphNode* focusNode) { + _focusNode = focusNode; + + if (_focusNode != nullptr) { + _previousFocusNodePosition = _focusNode->worldPosition(); + _previousFocusNodeRotation = glm::quat_cast(_focusNode->worldRotationMatrix()); + } +} + +void OrbitalNavigator::startInterpolateCameraDirection(const Camera& camera) { + glm::dvec3 camPos = camera.positionVec3(); + glm::dvec3 camDir = glm::normalize( + camera.rotationQuaternion() * glm::dvec3(0.0, 0.0, -1.0) + ); + glm::dvec3 centerPos = _focusNode->worldPosition(); + glm::dvec3 directionToCenter = glm::normalize(centerPos - camPos); + + double angle = glm::angle(camDir, directionToCenter); + + // Minimum is two second. Otherwise proportional to angle + _rotateToFocusNodeInterpolator.setInterpolationTime(glm::max(angle * 2.0, 2.0)); + _rotateToFocusNodeInterpolator.start(); +} + +bool OrbitalNavigator::followingNodeRotation() const { + return _followRotationInterpolator.value() >= 1.0; +} + +SceneGraphNode* OrbitalNavigator::focusNode() const { + return _focusNode; +} + +OrbitalNavigator::CameraRotationDecomposition + OrbitalNavigator::decomposeCameraRotation( + const glm::dvec3& cameraPosition, + const glm::dquat& cameraRotation, + const glm::dvec3& cameraLookUp, + const glm::dvec3& cameraViewDirection) +{ + glm::dmat4 inverseModelTransform = _focusNode->inverseModelTransform(); + glm::dmat4 modelTransform = _focusNode->modelTransform(); + glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(cameraPosition, 1)); + + SurfacePositionHandle posHandle = + _focusNode->calculateSurfacePositionHandle(cameraPositionModelSpace); + + glm::dvec3 directionFromSurfaceToCameraModelSpace = + posHandle.referenceSurfaceOutDirection; + glm::dvec3 directionFromSurfaceToCamera = + glm::normalize(glm::dmat3(modelTransform) * + directionFromSurfaceToCameraModelSpace); + + // To avoid problem with lookup in up direction we adjust is with the view direction + glm::dmat4 lookAtMat = glm::lookAt( + glm::dvec3(0.0, 0.0, 0.0), + -directionFromSurfaceToCamera, + normalize(cameraViewDirection + cameraLookUp)); + glm::dquat globalCameraRotation = glm::normalize(glm::quat_cast(inverse(lookAtMat))); + glm::dquat localCameraRotation = glm::inverse(globalCameraRotation) * cameraRotation; + + return { localCameraRotation, globalCameraRotation }; +} + +glm::dquat OrbitalNavigator::roll(double deltaTime, + const glm::dquat& localCameraRotation) const +{ + glm::dquat rollQuat = glm::angleAxis( + _mouseStates.localRollMouseVelocity().x * deltaTime, + glm::dvec3(0.0, 0.0, 1.0) + ); + return localCameraRotation * rollQuat; +} + +glm::dquat OrbitalNavigator::rotateLocally(double deltaTime, + const glm::dquat& localCameraRotation) const +{ + glm::dvec3 eulerAngles( + _mouseStates.localRotationMouseVelocity().y, + _mouseStates.localRotationMouseVelocity().x, + 0.0 + ); + glm::dquat rotationDiff = glm::dquat(eulerAngles * deltaTime); + return localCameraRotation * rotationDiff; +} + +glm::dquat OrbitalNavigator::interpolateLocalRotation( + double deltaTime, + const glm::dquat& localCameraRotation) +{ + if (_rotateToFocusNodeInterpolator.isInterpolating()) { + double t = _rotateToFocusNodeInterpolator.value(); + _rotateToFocusNodeInterpolator.setDeltaTime(deltaTime); + _rotateToFocusNodeInterpolator.step(); + glm::dquat result = glm::slerp( + localCameraRotation, + glm::dquat(glm::dvec3(0.0)), + glm::min(t * _rotateToFocusNodeInterpolator.deltaTimeScaled(), 1.0)); + if (angle(result) < 0.01) { + _rotateToFocusNodeInterpolator.end(); + } + return result; + } + else { + return localCameraRotation; + } +} + +glm::dvec3 OrbitalNavigator::translateHorizontally( + double deltaTime, + const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff, + const glm::dquat& globalCameraRotation, + const SurfacePositionHandle& positionHandle) const +{ + glm::dmat4 modelTransform = _focusNode->modelTransform(); + + glm::dvec3 outDirection = + glm::normalize(glm::dmat3(modelTransform) * + positionHandle.referenceSurfaceOutDirection); + + // Vector logic + glm::dvec3 posDiff = cameraPosition - objectPosition; + glm::dvec3 centerToReferenceSurface = glm::dmat3(modelTransform) * + positionHandle.centerToReferenceSurface; + glm::dvec3 centerToActualSurfaceModelSpace = positionHandle.centerToReferenceSurface + + positionHandle.referenceSurfaceOutDirection * positionHandle.heightToSurface; + glm::dvec3 centerToActualSurface = glm::dmat3(modelTransform) * + centerToActualSurfaceModelSpace; + glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface; + double distFromSurfaceToCamera = glm::length(actualSurfaceToCamera); + + // Final values to be used + double distFromCenterToSurface = length(centerToActualSurface); + double distFromCenterToCamera = length(posDiff); + + double speedScale = + distFromCenterToSurface > 0.0 ? + glm::clamp(distFromSurfaceToCamera / distFromCenterToSurface, 0.0, 1.0) : + 1.0; + + // Get rotation in camera space + glm::dvec3 eulerAngles = glm::dvec3( + -_mouseStates.globalRotationMouseVelocity().y * deltaTime, + -_mouseStates.globalRotationMouseVelocity().x * deltaTime, + 0) * speedScale; + glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles); + + // Transform to world space + glm::dquat rotationDiffWorldSpace = + globalCameraRotation * + rotationDiffCamSpace * + glm::inverse(globalCameraRotation); + + // Rotate and find the difference vector + glm::dvec3 rotationDiffVec3 = + (distFromCenterToCamera * outDirection) + * rotationDiffWorldSpace + - (distFromCenterToCamera * outDirection); + + // Add difference to position + return cameraPosition + rotationDiffVec3; +} + +glm::dvec3 OrbitalNavigator::followFocusNodeRotation( + const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff) const +{ + glm::dvec3 posDiff = cameraPosition - objectPosition; + glm::dvec3 rotationDiffVec3AroundCenter = + posDiff + * focusNodeRotationDiff + - (posDiff); + return cameraPosition + rotationDiffVec3AroundCenter; +} + +glm::dquat OrbitalNavigator::rotateGlobally( + const glm::dquat& globalCameraRotation, + const glm::dvec3& objectPosition, + const glm::dquat& focusNodeRotationDiff, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const +{ + glm::dmat4 modelTransform = _focusNode->modelTransform(); + + glm::dvec3 directionFromSurfaceToCamera = + glm::dmat3(modelTransform) * positionHandle.referenceSurfaceOutDirection; + + glm::dvec3 lookUpWhenFacingSurface = + glm::inverse(focusNodeRotationDiff) * + globalCameraRotation * glm::dvec3(0.0, 1.0, 0.0); + glm::dmat4 lookAtMat = glm::lookAt( + glm::dvec3(0.0, 0.0, 0.0), + -directionFromSurfaceToCamera, + lookUpWhenFacingSurface); + return glm::normalize(glm::quat_cast(glm::inverse(lookAtMat))); +} + +glm::dvec3 OrbitalNavigator::translateVertically( + double deltaTime, + const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const +{ + glm::dmat4 modelTransform = _focusNode->modelTransform(); + + glm::dvec3 posDiff = cameraPosition - objectPosition; + + glm::dvec3 centerToReferenceSurface = + glm::dmat3(modelTransform) * positionHandle.centerToReferenceSurface; + glm::dvec3 centerToActualSurfaceModelSpace = + positionHandle.centerToReferenceSurface + + positionHandle.referenceSurfaceOutDirection * positionHandle.heightToSurface; + glm::dvec3 centerToActualSurface = + glm::dmat3(modelTransform) * centerToActualSurfaceModelSpace; + glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface; + + return cameraPosition - + actualSurfaceToCamera * _mouseStates.truckMovementMouseVelocity().y * deltaTime; +} + +glm::dquat OrbitalNavigator::rotateHorizontally( + double deltaTime, + const glm::dquat& globalCameraRotation, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) const +{ + glm::dmat4 modelTransform = _focusNode->modelTransform(); + + glm::dvec3 directionFromSurfaceToCameraModelSpace = + positionHandle.referenceSurfaceOutDirection; + glm::dvec3 directionFromSurfaceToCamera = + glm::normalize(glm::dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace); + + glm::dquat cameraRollRotation = + glm::angleAxis( + _mouseStates.globalRollMouseVelocity().x * + deltaTime, directionFromSurfaceToCamera + ); + return cameraRollRotation * globalCameraRotation; +} + +glm::dvec3 OrbitalNavigator::pushToSurface( + double minHeightAboveGround, + const glm::dvec3& cameraPosition, + const glm::dvec3& objectPosition, + const SurfacePositionHandle& positionHandle) const +{ + glm::dmat4 modelTransform = _focusNode->modelTransform(); + + glm::dvec3 posDiff = cameraPosition - objectPosition; + glm::dvec3 referenceSurfaceOutDirection = + glm::dmat3(modelTransform) * positionHandle.referenceSurfaceOutDirection; + glm::dvec3 centerToReferenceSurface = + glm::dmat3(modelTransform) * positionHandle.centerToReferenceSurface; + glm::dvec3 centerToActualSurfaceModelSpace = + positionHandle.centerToReferenceSurface + + positionHandle.referenceSurfaceOutDirection * positionHandle.heightToSurface; + glm::dvec3 centerToActualSurface = + glm::dmat3(modelTransform) * centerToActualSurfaceModelSpace; + glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface; + double surfaceToCameraSigned = + glm::length(actualSurfaceToCamera) * + glm::sign(dot(actualSurfaceToCamera, referenceSurfaceOutDirection)); + + return cameraPosition + referenceSurfaceOutDirection * + glm::max(minHeightAboveGround - surfaceToCameraSigned, 0.0); +} + +glm::dquat OrbitalNavigator::interpolateRotationDifferential( + double deltaTime, + double interpolationTime, + const glm::dquat& rotationDiff, + const glm::dvec3& objectPosition, + const glm::dvec3& cameraPosition, + const SurfacePositionHandle& positionHandle) +{ + glm::dmat4 modelTransform = _focusNode->modelTransform(); + + double maximumDistanceForRotation = glm::length( + glm::dmat3(modelTransform) * positionHandle.centerToReferenceSurface + ) * _followFocusNodeRotationDistance; + double distanceToCamera = glm::length(cameraPosition - objectPosition); + + // Interpolate with a negative delta time if distance is too large to follow + double interpolationSign = glm::sign(maximumDistanceForRotation - distanceToCamera); + + _followRotationInterpolator.setInterpolationTime(interpolationTime); + _followRotationInterpolator.setDeltaTime(interpolationSign * deltaTime); + _followRotationInterpolator.step(); + + return glm::slerp( + glm::dquat(glm::dvec3(0.0)), + rotationDiff, + _followRotationInterpolator.value() + ); +} + +SurfacePositionHandle OrbitalNavigator::calculateSurfacePositionHandle( + const glm::dvec3 cameraPositionWorldSpace) +{ + glm::dmat4 inverseModelTransform = _focusNode->inverseModelTransform(); + glm::dvec3 cameraPositionModelSpace = + glm::dvec3(inverseModelTransform * glm::dvec4(cameraPositionWorldSpace, 1)); + SurfacePositionHandle posHandle = + _focusNode->calculateSurfacePositionHandle(cameraPositionModelSpace); + return posHandle; +} + +} // namespace interaction +} // namespace openspace diff --git a/src/network/parallelconnection.cpp b/src/network/parallelconnection.cpp index 18ef602172..71c8f603ad 100644 --- a/src/network/parallelconnection.cpp +++ b/src/network/parallelconnection.cpp @@ -66,8 +66,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -580,14 +580,16 @@ void ParallelConnection::dataMessageReceived(const std::vector& messageCon datamessagestructures::CameraKeyframe kf(buffer); kf._timestamp = calculateBufferedKeyframeTime(kf._timestamp); - OsEng.interactionHandler().removeKeyframesAfter(kf._timestamp); - interaction::KeyframeInteractionMode::CameraPose pose; + OsEng.navigationHandler().keyframeNavigator().removeKeyframesAfter( + kf._timestamp); + interaction::KeyframeNavigator::CameraPose pose; pose.focusNode = kf._focusNode; pose.position = kf._position; pose.rotation = kf._rotation; pose.followFocusNodeRotation = kf._followNodeRotation; - OsEng.interactionHandler().addKeyframe(kf._timestamp, pose); + OsEng.navigationHandler().keyframeNavigator().addKeyframe( + kf._timestamp, pose); break; } case datamessagestructures::Type::TimeData: { @@ -755,7 +757,7 @@ void ParallelConnection::connectionStatusMessageReceived(const std::vector setStatus(status); - OsEng.interactionHandler().clearKeyframes(); + OsEng.navigationHandler().keyframeNavigator().clearKeyframes(); OsEng.timeManager().clearKeyframes(); } @@ -1012,7 +1014,7 @@ void ParallelConnection::sendScript(std::string script) { } void ParallelConnection::resetTimeOffset() { - OsEng.interactionHandler().clearKeyframes(); + OsEng.navigationHandler().keyframeNavigator().clearKeyframes(); OsEng.timeManager().clearKeyframes(); std::lock_guard latencyLock(_latencyMutex); _latencyDiffs.clear(); @@ -1082,21 +1084,21 @@ const std::string& ParallelConnection::hostName() { } void ParallelConnection::sendCameraKeyframe() { - SceneGraphNode* focusNode = OsEng.interactionHandler().focusNode(); + SceneGraphNode* focusNode = OsEng.navigationHandler().focusNode(); if (!focusNode) { return; } // Create a keyframe with current position and orientation of camera datamessagestructures::CameraKeyframe kf; - kf._position = OsEng.interactionHandler().focusNodeToCameraVector(); + kf._position = OsEng.navigationHandler().focusNodeToCameraVector(); - kf._followNodeRotation = OsEng.interactionHandler().interactionMode()->followingNodeRotation(); + kf._followNodeRotation = OsEng.navigationHandler().orbitalNavigator().followingNodeRotation(); if (kf._followNodeRotation) { kf._position = glm::inverse(focusNode->worldRotationMatrix()) * kf._position; - kf._rotation = OsEng.interactionHandler().focusNodeToCameraRotation(); + kf._rotation = OsEng.navigationHandler().focusNodeToCameraRotation(); } else { - kf._rotation = OsEng.interactionHandler().camera()->rotationQuaternion(); + kf._rotation = OsEng.navigationHandler().camera()->rotationQuaternion(); } kf._focusNode = focusNode->name(); diff --git a/src/query/query.cpp b/src/query/query.cpp index dadc2bc922..e2d205441a 100644 --- a/src/query/query.cpp +++ b/src/query/query.cpp @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index bc3e2e7880..de6fa7e52f 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -158,6 +158,17 @@ void Renderable::render(const RenderData& data, RendererTasks&) { void Renderable::render(const RenderData&) {} +SurfacePositionHandle Renderable::calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) +{ + glm::dvec3 directionFromCenterToTarget = glm::normalize(targetModelSpace); + return { + directionFromCenterToTarget * static_cast(boundingSphere()), + directionFromCenterToTarget, + 0.0 + }; +} + void Renderable::setPscUniforms(ghoul::opengl::ProgramObject& program, const Camera& camera, const PowerScaledCoordinate& position) diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 65314e2d71..8d75ff175f 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 5147d0bde0..2f65a7b5d7 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 24d30087ab..9e0bc937ec 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -477,6 +477,21 @@ void SceneGraphNode::setDependencies(const std::vector& depende } } +SurfacePositionHandle SceneGraphNode::calculateSurfacePositionHandle( + const glm::dvec3& targetModelSpace) +{ + if (_renderable) { + return _renderable->calculateSurfacePositionHandle(targetModelSpace); + } + else { + return { + glm::dvec3(0.0, 0.0, 0.0), + glm::normalize(targetModelSpace), + 0.0 + }; + } +} + const std::vector& SceneGraphNode::dependencies() const { return _dependencies; } diff --git a/src/util/camera.cpp b/src/util/camera.cpp index a7ecb6b0c9..f185fb4699 100644 --- a/src/util/camera.cpp +++ b/src/util/camera.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include From a232a1a0a777601b197f3da883ea693607693164 Mon Sep 17 00:00:00 2001 From: Kalle Bladin Date: Fri, 14 Jul 2017 22:48:32 +0200 Subject: [PATCH 191/192] Fix compilation warnings. --- .../globebrowsing/cache/texturecontainer.h | 3 ++- .../chunk/culling/frustumculler.cpp | 2 +- .../globebrowsing/globebrowsingmodule_lua.inl | 1 - modules/globebrowsing/globes/pointglobe.cpp | 22 +++++++++---------- modules/globebrowsing/meshes/trianglesoup.h | 1 - .../rendering/layer/layeradjustment.cpp | 10 ++++----- .../rendering/layer/layermanager.cpp | 3 +++ .../tile/rawtiledatareader/tiledatatype.cpp | 17 ++++++++++---- .../tile/tileprovider/defaulttileprovider.cpp | 2 -- .../tile/tileprovider/tileprovider.cpp | 4 ---- .../tile/tileprovider/tileproviderbylevel.cpp | 3 ++- 11 files changed, 37 insertions(+), 31 deletions(-) diff --git a/modules/globebrowsing/cache/texturecontainer.h b/modules/globebrowsing/cache/texturecontainer.h index 5035587abd..bcab70e17c 100644 --- a/modules/globebrowsing/cache/texturecontainer.h +++ b/modules/globebrowsing/cache/texturecontainer.h @@ -68,8 +68,9 @@ public: private: std::vector> _textures; - size_t _freeTexture; + const TileTextureInitData _initData; + size_t _freeTexture; size_t _numTextures; }; diff --git a/modules/globebrowsing/chunk/culling/frustumculler.cpp b/modules/globebrowsing/chunk/culling/frustumculler.cpp index 090d91ba4a..8d3c5ee849 100644 --- a/modules/globebrowsing/chunk/culling/frustumculler.cpp +++ b/modules/globebrowsing/chunk/culling/frustumculler.cpp @@ -40,7 +40,7 @@ bool FrustumCuller::isCullable(const Chunk& chunk, const RenderData& data) { // Calculate the MVP matrix glm::dmat4 modelTransform = chunk.owner().modelTransform(); glm::dmat4 viewTransform = glm::dmat4(data.camera.combinedViewMatrix()); - glm::dmat4 modelViewProjectionTransform = glm::dmat4(data.camera.projectionMatrix()) + glm::dmat4 modelViewProjectionTransform = glm::dmat4(data.camera.sgctInternal.projectionMatrix()) * viewTransform * modelTransform; const std::vector& corners = chunk.getBoundingPolyhedronCorners(); diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index c5fe4bf5db..0ac27b6baf 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -48,7 +48,6 @@ int addLayer(lua_State* L) { // Argument locations const int GlobeLocation = -3; const int LayerGroupLocation = -2; - const int DictionaryLocation = -1; int nArguments = lua_gettop(L); if (nArguments != 3) { diff --git a/modules/globebrowsing/globes/pointglobe.cpp b/modules/globebrowsing/globes/pointglobe.cpp index f1cc79a4c3..110571ae35 100644 --- a/modules/globebrowsing/globes/pointglobe.cpp +++ b/modules/globebrowsing/globes/pointglobe.cpp @@ -69,14 +69,14 @@ bool PointGlobe::initialize() { glBindVertexArray(_vaoID); - std::array quadVertexData = { - glm::vec2(-1.0f, -1.0f), - glm::vec2(1.0f, -1.0f), - glm::vec2(-1.0f, 1.0f), - glm::vec2(-1.0f, 1.0f), - glm::vec2(1.0f, -1.0f), - glm::vec2(1.0f, 1.0f) - }; + std::array quadVertexData = {{ + glm::vec2(-1.0f, -1.0f), + glm::vec2(1.0f, -1.0f), + glm::vec2(-1.0f, 1.0f), + glm::vec2(-1.0f, 1.0f), + glm::vec2(1.0f, -1.0f), + glm::vec2(1.0f, 1.0f) + }}; // Vertex buffer glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferID); @@ -121,7 +121,7 @@ void PointGlobe::render(const RenderData& data) { float avgRadius = _owner.ellipsoid().averageRadius(); float lightIntensity = _lightIntensity.value() * data.modelTransform.scale * avgRadius / distanceToBody; float lightIntensityClamped = glm::min(lightIntensity, _intensityClamp.value()); - float lightOverflow = glm::max(lightIntensity - lightIntensityClamped, 0.0f); + //float lightOverflow = glm::max(lightIntensity - lightIntensityClamped, 0.0f); float billboardRadius = lightIntensityClamped * distanceToBody; glm::dmat4 scaleTransform = glm::scale(glm::dmat4(1.0), glm::dvec3(billboardRadius)); @@ -134,8 +134,8 @@ void PointGlobe::render(const RenderData& data) { glm::inverse(rotationTransform) * scaleTransform; // Scale glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; - glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition)); - glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun; + //glm::vec3 directionToSun = glm::normalize(glm::vec3(0) - glm::vec3(bodyPosition)); + //glm::vec3 directionToSunViewSpace = glm::mat3(data.camera.combinedViewMatrix()) * directionToSun; _programObject->setUniform("lightIntensityClamped", lightIntensityClamped); diff --git a/modules/globebrowsing/meshes/trianglesoup.h b/modules/globebrowsing/meshes/trianglesoup.h index d754b0b244..5085003cec 100644 --- a/modules/globebrowsing/meshes/trianglesoup.h +++ b/modules/globebrowsing/meshes/trianglesoup.h @@ -83,7 +83,6 @@ protected: GLfloat position[4]; GLfloat texture[2]; GLfloat normal[3]; - private: GLubyte padding[28]; // Pads the struct out to 64 bytes for performance increase }; diff --git a/modules/globebrowsing/rendering/layer/layeradjustment.cpp b/modules/globebrowsing/rendering/layer/layeradjustment.cpp index 80b038612b..fad6678097 100644 --- a/modules/globebrowsing/rendering/layer/layeradjustment.cpp +++ b/modules/globebrowsing/rendering/layer/layeradjustment.cpp @@ -35,11 +35,6 @@ namespace { LayerAdjustment::LayerAdjustment() : properties::PropertyOwner("adjustment") - , _typeOption( - "type", - "Type", - properties::OptionProperty::DisplayType::Dropdown - ) , chromaKeyColor( "chromaKeyColor", "Chroma key color", @@ -54,6 +49,11 @@ LayerAdjustment::LayerAdjustment() 0, 1 ) + , _typeOption( + "type", + "Type", + properties::OptionProperty::DisplayType::Dropdown + ) , _onChangeCallback([](){}) { // Add options to option properties diff --git a/modules/globebrowsing/rendering/layer/layermanager.cpp b/modules/globebrowsing/rendering/layer/layermanager.cpp index b3f2aabb8a..b2a2a98e24 100644 --- a/modules/globebrowsing/rendering/layer/layermanager.cpp +++ b/modules/globebrowsing/rendering/layer/layermanager.cpp @@ -149,6 +149,9 @@ TileTextureInitData LayerManager::getTileTextureInitData(layergroupid::GroupID i } default: { ghoul_assert(false, "Unknown layer group ID"); + size_t tileSize = preferredTileSize ? preferredTileSize : 512; + return TileTextureInitData(tileSize, tileSize, GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::Format::BGRA); } } } diff --git a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp index 03a08c4ed0..4278175d9b 100644 --- a/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp +++ b/modules/globebrowsing/tile/rawtiledatareader/tiledatatype.cpp @@ -415,7 +415,10 @@ size_t numberOfRasters(ghoul::opengl::Texture::Format format) { case ghoul::opengl::Texture::Format::BGR: return 3; case ghoul::opengl::Texture::Format::RGBA:; // Intentional fallthrough case ghoul::opengl::Texture::Format::BGRA: return 4; - default: ghoul_assert(false, "Unknown format"); + default: { + ghoul_assert(false, "Unknown format"); + return 0; + } } } @@ -430,8 +433,10 @@ size_t numberOfBytes(GLenum glType) { case GL_HALF_FLOAT: return sizeof(GLhalf); case GL_FLOAT: return sizeof(GLfloat); case GL_DOUBLE: return sizeof(GLdouble); - default: + default: { ghoul_assert(false, "Unknown data type"); + return 0; + } } } @@ -447,8 +452,10 @@ size_t getMaximumValue(GLenum glType) { return size_t(1) << 32; case GL_INT: return 1 << 31; - default: + default: { ghoul_assert(false, "Unknown data type"); + return 0; + } } } @@ -470,8 +477,10 @@ float interpretFloat(GLenum glType, const char* src) { return static_cast(*reinterpret_cast(src)); case GL_DOUBLE: return static_cast(*reinterpret_cast(src)); - default: + default: { ghoul_assert(false, "Unknown data type"); + return 0; + } } } diff --git a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp index 63496682e5..e7343007f0 100644 --- a/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/defaulttileprovider.cpp @@ -197,8 +197,6 @@ void DefaultTileProvider::initTexturesFromLoadedData() { void DefaultTileProvider::initAsyncTileDataReader(TileTextureInitData initData) { std::string _loggerCat = "DefaultTileProvider : " + _name; - RawTileDataReader* tileDataReader = nullptr; - RawTileDataReader::PerformPreprocessing preprocess = _performPreProcessing ? RawTileDataReader::PerformPreprocessing::Yes : RawTileDataReader::PerformPreprocessing::No; diff --git a/modules/globebrowsing/tile/tileprovider/tileprovider.cpp b/modules/globebrowsing/tile/tileprovider/tileprovider.cpp index b0798b4929..31f4eadc26 100644 --- a/modules/globebrowsing/tile/tileprovider/tileprovider.cpp +++ b/modules/globebrowsing/tile/tileprovider/tileprovider.cpp @@ -34,10 +34,6 @@ #include -namespace { - const char* KeyType = "Type"; -} - namespace openspace { namespace globebrowsing { namespace tileprovider { diff --git a/modules/globebrowsing/tile/tileprovider/tileproviderbylevel.cpp b/modules/globebrowsing/tile/tileprovider/tileproviderbylevel.cpp index 92438fbeb3..28304146bf 100644 --- a/modules/globebrowsing/tile/tileprovider/tileproviderbylevel.cpp +++ b/modules/globebrowsing/tile/tileprovider/tileproviderbylevel.cpp @@ -29,6 +29,8 @@ #include namespace { + const char* _loggerCat = "TileProviderByLevel"; + const char* KeyProviders = "LevelTileProviders"; const char* KeyMaxLevel = "MaxLevel"; const char* KeyTileProvider = "TileProvider"; @@ -46,7 +48,6 @@ TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) layergroupid::GroupID layerGroupID; dictionary.getValue(KeyLayerGroupID, layerGroupID); - const char* _loggerCat = ("TileProviderByLevel" + name).c_str(); ghoul::Dictionary providers; if (dictionary.hasKeyAndValue(KeyProviders)) { From 0dc96c3bc82c525205c5096aaba78f69ff35ee42 Mon Sep 17 00:00:00 2001 From: Matthew Territo Date: Fri, 14 Jul 2017 18:22:02 -0600 Subject: [PATCH 192/192] default, osirisrex, & satellites --- data/scene/default.scene | 2 +- data/scene/osirisrex.scene | 2 +- data/scene/satellites.scene | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/scene/default.scene b/data/scene/default.scene index 3714385858..981cbf87ab 100644 --- a/data/scene/default.scene +++ b/data/scene/default.scene @@ -29,7 +29,7 @@ function postInitialization() openspace.addVirtualProperty("BoolProperty", "Show Trails", "*Trail.renderable.enabled", true, nil, nil) - openspace.resetCameraDirection() + openspace.navigation.resetCameraDirection() openspace.printInfo("Done setting default values") end diff --git a/data/scene/osirisrex.scene b/data/scene/osirisrex.scene index f5fff215a9..79c1e58e67 100644 --- a/data/scene/osirisrex.scene +++ b/data/scene/osirisrex.scene @@ -46,7 +46,7 @@ function postInitialization() openspace.printInfo("Done setting default values") openspace.loadMission("${OPENSPACE_DATA}/scene/missions/osirisrex/osirisrex/osirisrex.mission") - openspace.resetCameraDirection() + openspace.navigation.resetCameraDirection() end return { diff --git a/data/scene/satellites.scene b/data/scene/satellites.scene index 20eed4c4d4..5e09f29196 100644 --- a/data/scene/satellites.scene +++ b/data/scene/satellites.scene @@ -32,7 +32,7 @@ function postInitialization() openspace.setPropertyValue("EarthTrail.renderable.enabled", false) openspace.setPropertyValue("Earth.renderable.performShading", false) - openspace.resetCameraDirection() + openspace.navigation.resetCameraDirection() openspace.printInfo("Done setting default values")