diff --git a/.github/workflows/build-all-on-macos.yml b/.github/workflows/build-all-on-macos.yml
index d6db7b7..7539dd9 100644
--- a/.github/workflows/build-all-on-macos.yml
+++ b/.github/workflows/build-all-on-macos.yml
@@ -54,8 +54,19 @@ jobs:
echo "current working directory" && pwd
cd EmotiBitFirmwareInstaller
xcodebuild -project EmotiBitFirmwareInstaller.xcodeproj -scheme Release
+ build-slideplayer-macos:
+ needs: clone-macos
+ runs-on: [self-hosted, macOS]
+ environment: RUNNER-MACOS
+ steps:
+ - name: build using xcode
+ working-directory: ${{ vars.OFXEMOTIBIT_DIR }}
+ run: |
+ echo "current working directory" && pwd
+ cd SlidePlayer
+ xcodebuild -project SlidePlayer.xcodeproj -scheme Release
upload-artifact-macos:
- needs: [build-oscilloscope-macos, build-dataparser-macos, build-firmwareinstaller-macos]
+ needs: [build-oscilloscope-macos, build-dataparser-macos, build-firmwareinstaller-macos, build-slideplayer-macos]
if: github.ref == 'refs/heads/dev'
runs-on: [self-hosted, macOS]
environment: RUNNER-MACOS
@@ -76,6 +87,7 @@ jobs:
mv EmotiBitOscilloscope/bin/EmotiBitOscilloscope.app stageRelease/EmotiBitSoftware-macos-${{ steps.get_version.outputs.version }}
mv EmotiBitDataParser/bin/EmotiBitDataParser.app stageRelease/EmotiBitSoftware-macos-${{ steps.get_version.outputs.version }}
mv EmotiBitFirmwareInstaller/bin/EmotiBitFirmwareInstaller.app stageRelease/EmotiBitSoftware-macos-${{ steps.get_version.outputs.version }}
+ mv SlidePlayer/bin/SlidePlayer.app stageRelease/EmotiBitSoftware-macos-${{ steps.get_version.outputs.version }}
- name: copy SiLabs drivers
working-directory: ${{ vars.ADDONS_DIR }}
run: |
diff --git a/.github/workflows/build-all-on-win.yaml b/.github/workflows/build-all-on-win.yaml
index 202cdca..39833fb 100644
--- a/.github/workflows/build-all-on-win.yaml
+++ b/.github/workflows/build-all-on-win.yaml
@@ -61,8 +61,20 @@ jobs:
echo "current working directory" && pwd
cd EmotiBitFirmwareInstaller
MSBuild EmotiBitFirmwareInstaller.sln -t:Build -p:Configuration=Release
+ build-slideplayer-windows:
+ needs: clone-windows
+ runs-on: [self-hosted, Windows]
+ environment: RUNNER-WINDOWS
+ steps:
+ - name: build using MSBuild
+ shell: cmd
+ working-directory: ${{ vars.OFXEMOTIBIT_DIR }}
+ run: |
+ echo "current working directory" && pwd
+ cd SlidePlayer
+ MSBuild SlidePlayer.sln -t:Build -p:Configuration=Release
build-installer-windows:
- needs: [build-oscilloscope-windows, build-dataparser-windows, build-firmwareinstaller-windows]
+ needs: [build-oscilloscope-windows, build-dataparser-windows, build-firmwareinstaller-windows, build-slideplayer-windows]
if: github.ref == 'refs/heads/dev'
runs-on: [self-hosted, Windows]
environment: RUNNER-WINDOWS
diff --git a/.gitignore b/.gitignore
index 55f085a..3a07fbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,6 +29,12 @@
*.a
*.lib
+# build folders
+**/build/
+
+# docs
+**/docs/
+
# Executables
*.exe
*.out
@@ -60,3 +66,6 @@ EmotiBitInstaller/redist/
# testing
tests/EmotiBitDataParser/sample_data/2025-06-27_09-56-59-929206*.csv
+
+# macOS
+**/.DS_Store
diff --git a/EmotiBitInstaller/EmotiBitInstaller.iss b/EmotiBitInstaller/EmotiBitInstaller.iss
index fb55a2b..740d5fb 100644
--- a/EmotiBitInstaller/EmotiBitInstaller.iss
+++ b/EmotiBitInstaller/EmotiBitInstaller.iss
@@ -57,6 +57,13 @@ Source: "..\EmotiBitFirmwareInstaller\bin\data\esp32\*"; DestDir: "{app}\EmotiBi
Source: "..\EmotiBitFirmwareInstaller\bin\data\exec\win\*"; DestDir: "{app}\EmotiBit FirmwareInstaller\data\exec\win"
Source: "..\EmotiBitFirmwareInstaller\bin\data\instructions\*.jpg"; DestDir: "{app}\EmotiBit FirmwareInstaller\data\instructions"
+; EmotiBit SlidePlayer
+Source: "..\SlidePlayer\bin\SlidePlayer.exe"; DestDir: "{app}\EmotiBit SlidePlayer"
+Source: "..\SlidePlayer\bin\*.dll"; DestDir: "{app}\EmotiBit SlidePlayer"
+Source: "..\SlidePlayer\bin\data\emotibitSlidePlayerSettings.json"; DestDir: "{app}\EmotiBit SlidePlayer\data"
+; Example slides
+Source: "..\SlidePlayer\bin\data\example_slides\*"; DestDir: "{app}\EmotiBit SlidePlayer\data\example_slides"; Flags: recursesubdirs
+
; VC++ 2017 Redistributable
Source: "redist\vc_redist.x64.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
@@ -68,6 +75,7 @@ Source: "..\EmotiBitIcons\icoFiles\EmotiBitLogo.ico"; DestDir: "{app}"
Name: "{group}\EmotiBit Oscilloscope"; Filename: "{app}\EmotiBit Oscilloscope\EmotiBitOscilloscope.exe"; WorkingDir: "{app}\EmotiBit Oscilloscope"
Name: "{group}\EmotiBit DataParser"; Filename: "{app}\EmotiBit DataParser\EmotiBitDataParser.exe"; WorkingDir: "{app}\EmotiBit DataParser"
Name: "{group}\EmotiBit FirmwareInstaller"; Filename: "{app}\EmotiBit FirmwareInstaller\EmotiBitFirmwareInstaller.exe"; WorkingDir: "{app}\EmotiBit FirmwareInstaller"
+Name: "{group}\EmotiBit SlidePlayer"; Filename: "{app}\EmotiBit SlidePlayer\SlidePlayer.exe"; WorkingDir: "{app}\EmotiBit SlidePlayer"
[Run]
; Install VC++ 2017 Redistributable if not already installed
@@ -79,6 +87,7 @@ Filename: "{tmp}\vc_redist.x64.exe"; Parameters: "/passive /norestart"; StatusMs
Type: filesandordirs; Name: "{app}\EmotiBit Oscilloscope"
Type: filesandordirs; Name: "{app}\EmotiBit DataParser"
Type: filesandordirs; Name: "{app}\EmotiBit FirmwareInstaller"
+Type: filesandordirs; Name: "{app}\EmotiBit SlidePlayer"
; Delete the parent EmotiBit folder if empty after above deletions
Type: dirifempty; Name: "{app}"
diff --git a/SlidePlayer/.clang-format b/SlidePlayer/.clang-format
new file mode 100644
index 0000000..61427fb
--- /dev/null
+++ b/SlidePlayer/.clang-format
@@ -0,0 +1,8 @@
+BasedOnStyle: Google
+BreakBeforeBraces: Allman
+IndentWidth: 4
+UseTab: Never
+AllowShortFunctionsOnASingleLine: None
+AllowShortBlocksOnASingleLine: Never
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
diff --git a/SlidePlayer/.clang-tidy b/SlidePlayer/.clang-tidy
new file mode 100644
index 0000000..55ac74d
--- /dev/null
+++ b/SlidePlayer/.clang-tidy
@@ -0,0 +1,55 @@
+Checks: >
+ readability-identifier-naming,
+ readability-identifier-length,
+ modernize-use-nullptr,
+ -modernize-use-override,
+ modernize-use-default-member-init,
+ bugprone-*,
+ -bugprone-easily-swappable-parameters
+
+CheckOptions:
+ # Local variables: snake_case, no prefix
+ - key: readability-identifier-naming.LocalVariableCase
+ value: lower_case
+ - key: readability-identifier-naming.LocalVariablePrefix
+ value: ''
+
+ # Parameters: snake_case, no prefix
+ - key: readability-identifier-naming.ParameterCase
+ value: lower_case
+ - key: readability-identifier-naming.ParameterPrefix
+ value: ''
+ - key: readability-identifier-naming.ParameterMinLength
+ value: '1'
+
+ # Member variables: snake_case with trailing underscore
+ - key: readability-identifier-naming.MemberCase
+ value: lower_case
+ - key: readability-identifier-naming.MemberSuffix
+ value: '_'
+
+ # Functions and methods: camelCase (Google style)
+ - key: readability-identifier-naming.FunctionCase
+ value: camelBack
+ - key: readability-identifier-naming.MethodCase
+ value: camelBack
+
+ # Classes and structs: CamelCase
+ - key: readability-identifier-naming.ClassCase
+ value: CamelCase
+ - key: readability-identifier-naming.StructCase
+ value: CamelCase
+
+ # Constants: kCamelCase (Google style)
+ - key: readability-identifier-naming.ConstantCase
+ value: CamelCase
+ - key: readability-identifier-naming.ConstantPrefix
+ value: 'k'
+
+ # Allow single-character names (e.g. loop counters, x/y coords)
+ - key: readability-identifier-length.MinimumVariableNameLength
+ value: '1'
+ - key: readability-identifier-length.MinimumParameterNameLength
+ value: '1'
+ - key: readability-identifier-length.MinimumLoopCounterNameLength
+ value: '1'
diff --git a/SlidePlayer/CMakeLists.txt b/SlidePlayer/CMakeLists.txt
new file mode 100644
index 0000000..4d3e433
--- /dev/null
+++ b/SlidePlayer/CMakeLists.txt
@@ -0,0 +1,207 @@
+cmake_minimum_required(VERSION 3.20)
+
+set(CMAKE_OSX_DEPLOYMENT_TARGET "11.5" CACHE STRING "Minimum macOS version")
+
+project(SlidePlayer)
+
+set(CMAKE_CXX_STANDARD 23)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# ── Paths ──────────────────────────────────────────────────────────────────────
+set(OF_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
+set(OF_LIBS "${OF_ROOT}/libs")
+set(OF_COMPILED "${OF_LIBS}/openFrameworksCompiled/lib/osx")
+set(OF_THIRD_PARTY "${OF_COMPILED}/build/output")
+set(OF_ADDONS "${OF_ROOT}/addons")
+
+# ── Shared app sources (excludes main.cpp so tests can reuse without conflict) ─
+file(GLOB MM_SOURCES "src/*.mm")
+set(OF_APP_SOURCES
+ src/ofApp.cpp
+ ${MM_SOURCES}
+ ${OF_ADDONS}/ofxJSON/src/ofxJSONElement.cpp
+ ${OF_ADDONS}/ofxJSON/libs/jsoncpp/src/jsoncpp.cpp
+)
+
+# ── Shared compile options ─────────────────────────────────────────────────────
+set(OF_COMPILE_OPTIONS
+ -stdlib=libc++
+ -Wall
+ -Werror=return-type
+ -fexceptions
+ -fpascal-strings
+ -fobjc-arc
+ -x objective-c++ # OF headers require ObjC++ on macOS
+)
+
+# ── Shared compile definitions ─────────────────────────────────────────────────
+set(OF_COMPILE_DEFINITIONS
+ __MACOSX_CORE__
+ USE_FMOD=0
+ GL_SILENCE_DEPRECATION=1
+ GLES_SILENCE_DEPRECATION=1
+ COREVIDEO_SILENCE_GL_DEPRECATION=1
+ GLM_FORCE_CTOR_INIT
+ GLM_ENABLE_EXPERIMENTAL
+)
+
+# ── Shared include directories ─────────────────────────────────────────────────
+set(OF_INCLUDE_DIRS
+ src
+ ${OF_LIBS}/openFrameworks
+ ${OF_LIBS}/openFrameworks/3d
+ ${OF_LIBS}/openFrameworks/app
+ ${OF_LIBS}/openFrameworks/communication
+ ${OF_LIBS}/openFrameworks/events
+ ${OF_LIBS}/openFrameworks/gl
+ ${OF_LIBS}/openFrameworks/graphics
+ ${OF_LIBS}/openFrameworks/math
+ ${OF_LIBS}/openFrameworks/sound
+ ${OF_LIBS}/openFrameworks/types
+ ${OF_LIBS}/openFrameworks/utils
+ ${OF_LIBS}/openFrameworks/video
+ ${OF_LIBS}/freetype/include
+ ${OF_LIBS}/freetype/include/freetype2
+ ${OF_LIBS}/glew/include
+ ${OF_LIBS}/FreeImage/include
+ ${OF_LIBS}/tess2/include
+ ${OF_LIBS}/cairo/include
+ ${OF_LIBS}/rtAudio/include
+ ${OF_LIBS}/glfw/include
+ ${OF_LIBS}/utf8/include
+ ${OF_LIBS}/json/include
+ ${OF_LIBS}/glm/include
+ ${OF_LIBS}/curl/include
+ ${OF_LIBS}/openssl/include
+ ${OF_LIBS}/uriparser/include
+ ${OF_LIBS}/pugixml/include
+ ${OF_LIBS}/brotli/include
+ ${OF_ADDONS}/ofxJSON/libs/jsoncpp/include
+ ${OF_ADDONS}/ofxJSON/src
+)
+
+# ── Shared static libraries ────────────────────────────────────────────────────
+set(OF_STATIC_LIBS
+ ${OF_COMPILED}/openFrameworks.a
+ ${OF_THIRD_PARTY}/FreeImage.a
+ ${OF_THIRD_PARTY}/libGLEW.a
+ ${OF_THIRD_PARTY}/libfreetype.a
+ ${OF_THIRD_PARTY}/libpugixml.a
+ ${OF_THIRD_PARTY}/libtess2.a
+ ${OF_THIRD_PARTY}/libcairo.a
+ ${OF_THIRD_PARTY}/libpixman-1.a
+ ${OF_THIRD_PARTY}/librtaudio.a
+ ${OF_THIRD_PARTY}/libglfw3.a
+ ${OF_THIRD_PARTY}/libpng.a
+ ${OF_THIRD_PARTY}/brotli.a
+ ${OF_THIRD_PARTY}/curl.a
+ ${OF_THIRD_PARTY}/openssl.a
+ ${OF_THIRD_PARTY}/uriparser.a
+ ${OF_THIRD_PARTY}/libfmt.a
+ ${OF_THIRD_PARTY}/zlib.a
+ objc
+)
+
+# ── macOS Frameworks ───────────────────────────────────────────────────────────
+find_library(FW_ACCELERATE Accelerate)
+find_library(FW_APP_KIT AppKit)
+find_library(FW_APPLICATION_SERVICES ApplicationServices)
+find_library(FW_AV_FOUNDATION AVFoundation)
+find_library(FW_AUDIO_TOOLBOX AudioToolbox)
+find_library(FW_COCOA Cocoa)
+find_library(FW_CORE_AUDIO CoreAudio)
+find_library(FW_CORE_FOUNDATION CoreFoundation)
+find_library(FW_CORE_MEDIA CoreMedia)
+find_library(FW_CORE_SERVICES CoreServices)
+find_library(FW_CORE_VIDEO CoreVideo)
+find_library(FW_FOUNDATION Foundation)
+find_library(FW_IO_KIT IOKit)
+find_library(FW_METAL Metal)
+find_library(FW_OPEN_GL OpenGL)
+find_library(FW_QUARTZ_CORE QuartzCore)
+find_library(FW_SECURITY Security)
+find_library(FW_SYSTEM_CONFIGURATION SystemConfiguration)
+
+set(OF_FRAMEWORKS
+ ${FW_ACCELERATE}
+ ${FW_APP_KIT}
+ ${FW_APPLICATION_SERVICES}
+ ${FW_AV_FOUNDATION}
+ ${FW_AUDIO_TOOLBOX}
+ ${FW_COCOA}
+ ${FW_CORE_AUDIO}
+ ${FW_CORE_FOUNDATION}
+ ${FW_CORE_MEDIA}
+ ${FW_CORE_SERVICES}
+ ${FW_CORE_VIDEO}
+ ${FW_FOUNDATION}
+ ${FW_IO_KIT}
+ ${FW_METAL}
+ ${FW_OPEN_GL}
+ ${FW_QUARTZ_CORE}
+ ${FW_SECURITY}
+ ${FW_SYSTEM_CONFIGURATION}
+)
+
+# ── Main application ───────────────────────────────────────────────────────────
+add_executable(${PROJECT_NAME} MACOSX_BUNDLE src/main.cpp ${OF_APP_SOURCES})
+
+target_compile_options(${PROJECT_NAME} PRIVATE ${OF_COMPILE_OPTIONS})
+target_compile_definitions(${PROJECT_NAME} PRIVATE ${OF_COMPILE_DEFINITIONS})
+target_include_directories(${PROJECT_NAME} PRIVATE ${OF_INCLUDE_DIRS})
+target_link_libraries(${PROJECT_NAME} PRIVATE ${OF_STATIC_LIBS} ${OF_FRAMEWORKS})
+target_link_options(${PROJECT_NAME} PRIVATE
+ -stdlib=libc++
+ -mmacosx-version-min=11.5
+)
+
+set_target_properties(${PROJECT_NAME} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin"
+)
+
+# ── Always copy JSON settings to app bundle Resources ─────────────────────────
+set(JSON_SRC "${CMAKE_CURRENT_SOURCE_DIR}/bin/data/emotibitSlidePlayerSettings.json")
+set(BUNDLE_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/bin/${PROJECT_NAME}.app/Contents/Resources")
+
+set(EXAMPLE_SLIDES_SRC "${CMAKE_CURRENT_SOURCE_DIR}/bin/data/example_slides")
+
+add_custom_target(copy_settings ALL
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${BUNDLE_RESOURCES}"
+ COMMAND ${CMAKE_COMMAND} -E copy "${JSON_SRC}" "${BUNDLE_RESOURCES}/emotibitSlidePlayerSettings.json"
+ COMMAND ${CMAKE_COMMAND} -E copy_directory "${EXAMPLE_SLIDES_SRC}" "${BUNDLE_RESOURCES}/example_slides"
+ COMMENT "Copying settings and example slides to app bundle Resources"
+)
+add_dependencies(copy_settings ${PROJECT_NAME})
+
+# ── Tests ──────────────────────────────────────────────────────────────────────
+enable_testing()
+
+include(FetchContent)
+FetchContent_Declare(
+ Catch2
+ GIT_REPOSITORY https://github.com/catchorg/Catch2.git
+ GIT_TAG v3.5.2
+)
+FetchContent_MakeAvailable(Catch2)
+
+add_executable(slideShow_tests
+ tests/test_parseSettings.cpp
+ tests/test_updateCurrentState.cpp
+ ${OF_APP_SOURCES}
+)
+
+target_compile_options(slideShow_tests PRIVATE ${OF_COMPILE_OPTIONS})
+target_compile_definitions(slideShow_tests PRIVATE ${OF_COMPILE_DEFINITIONS})
+target_include_directories(slideShow_tests PRIVATE ${OF_INCLUDE_DIRS})
+target_link_libraries(slideShow_tests PRIVATE
+ Catch2::Catch2WithMain
+ ${OF_STATIC_LIBS}
+ ${OF_FRAMEWORKS}
+)
+target_link_options(slideShow_tests PRIVATE
+ -stdlib=libc++
+ -mmacosx-version-min=11.5
+)
+
+include(Catch)
+catch_discover_tests(slideShow_tests)
diff --git a/SlidePlayer/Doxyfile b/SlidePlayer/Doxyfile
new file mode 100644
index 0000000..735ffbf
--- /dev/null
+++ b/SlidePlayer/Doxyfile
@@ -0,0 +1,27 @@
+PROJECT_NAME = "mock_slideShow"
+PROJECT_BRIEF = "EmotiBit slide player application"
+OUTPUT_DIRECTORY = docs
+
+# Input
+INPUT = src
+FILE_PATTERNS = *.h *.cpp
+RECURSIVE = NO
+
+# Enforce documentation
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_AS_ERROR = YES
+
+# Only document public members in headers
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = YES
+
+# Doxygen style
+JAVADOC_AUTOBRIEF = NO
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+
+# Output formats
+GENERATE_HTML = YES
+GENERATE_LATEX = NO
diff --git a/SlidePlayer/Makefile b/SlidePlayer/Makefile
new file mode 100644
index 0000000..177e172
--- /dev/null
+++ b/SlidePlayer/Makefile
@@ -0,0 +1,13 @@
+# Attempt to load a config.make file.
+# If none is found, project defaults in config.project.make will be used.
+ifneq ($(wildcard config.make),)
+ include config.make
+endif
+
+# make sure the the OF_ROOT location is defined
+ifndef OF_ROOT
+ OF_ROOT=$(realpath ../../..)
+endif
+
+# call the project makefile!
+include $(OF_ROOT)/libs/openFrameworksCompiled/project/makefileCommon/compile.project.mk
diff --git a/SlidePlayer/Project.xcconfig b/SlidePlayer/Project.xcconfig
new file mode 100644
index 0000000..40adc89
--- /dev/null
+++ b/SlidePlayer/Project.xcconfig
@@ -0,0 +1,18 @@
+//THE PATH TO THE ROOT OF OUR OF PATH RELATIVE TO THIS PROJECT.
+//THIS NEEDS TO BE DEFINED BEFORE CoreOF.xcconfig IS INCLUDED
+OF_PATH = ../../..
+
+//THIS HAS ALL THE HEADER AND LIBS FOR OF CORE
+#include "../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig"
+
+//ICONS - NEW IN 0072
+ICON_NAME_DEBUG = icon-debug.icns
+ICON_NAME_RELEASE = icon.icns
+ICON_FILE_PATH = $(OF_PATH)/libs/openFrameworksCompiled/project/osx/
+
+//IF YOU WANT AN APP TO HAVE A CUSTOM ICON - PUT THEM IN YOUR DATA FOLDER AND CHANGE ICON_FILE_PATH to:
+//ICON_FILE_PATH = bin/data/
+
+OTHER_CFLAGS = $(OF_CORE_CFLAGS)
+OTHER_LDFLAGS = $(OF_CORE_LIBS) $(OF_CORE_FRAMEWORKS)
+HEADER_SEARCH_PATHS = $(OF_CORE_HEADERS)
diff --git a/SlidePlayer/SlidePlayer.sln b/SlidePlayer/SlidePlayer.sln
new file mode 100644
index 0000000..bfa935f
--- /dev/null
+++ b/SlidePlayer/SlidePlayer.sln
@@ -0,0 +1,35 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SlidePlayer", "SlidePlayer.vcxproj", "{7FD42DF7-442E-479A-BA76-D0022F99702A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openframeworksLib", "..\..\..\libs\openFrameworksCompiled\project\vs\openframeworksLib.vcxproj", "{5837595D-ACA9-485C-8E76-729040CE4B0B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|Win32.Build.0 = Debug|Win32
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.ActiveCfg = Debug|x64
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Debug|x64.Build.0 = Debug|x64
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.ActiveCfg = Release|Win32
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|Win32.Build.0 = Release|Win32
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.ActiveCfg = Release|x64
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}.Release|x64.Build.0 = Release|x64
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|Win32.Build.0 = Debug|Win32
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.ActiveCfg = Debug|x64
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Debug|x64.Build.0 = Debug|x64
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.ActiveCfg = Release|Win32
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|Win32.Build.0 = Release|Win32
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.ActiveCfg = Release|x64
+ {5837595D-ACA9-485C-8E76-729040CE4B0B}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/SlidePlayer/SlidePlayer.vcxproj b/SlidePlayer/SlidePlayer.vcxproj
new file mode 100644
index 0000000..6f65d44
--- /dev/null
+++ b/SlidePlayer/SlidePlayer.vcxproj
@@ -0,0 +1,213 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0'))
+ 10.0
+ $(WindowsTargetPlatformVersion)
+
+
+ {7FD42DF7-442E-479A-BA76-D0022F99702A}
+ Win32Proj
+ SlidePlayer
+
+
+
+ Application
+ Unicode
+ v143
+
+
+ Application
+ Unicode
+ v143
+
+
+ Application
+ Unicode
+ true
+ v143
+
+
+ Application
+ Unicode
+ true
+ v143
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ bin\
+ obj\$(Platform)\$(Configuration)\
+ $(ProjectName)_debug
+ true
+ true
+
+
+ bin\
+ obj\$(Platform)\$(Configuration)\
+ $(ProjectName)_debug
+ true
+ true
+
+
+ bin\
+ obj\$(Platform)\$(Configuration)\
+ false
+
+
+ bin\
+ obj\$(Platform)\$(Configuration)\
+ false
+
+
+
+ Disabled
+ EnableFastChecks
+ %(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+ Level3
+ %(AdditionalIncludeDirectories);..\..\..\addons\ofxJSON\libs;..\..\..\addons\ofxJSON\libs\jsoncpp;..\..\..\addons\ofxJSON\libs\jsoncpp\include;..\..\..\addons\ofxJSON\libs\jsoncpp\include\json;..\..\..\addons\ofxJSON\libs\jsoncpp\src;..\..\..\addons\ofxJSON\src
+ CompileAsCpp
+ $(IntDir)%(RelativeDir)
+
+
+ true
+ Console
+ false
+ %(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+
+
+
+
+
+ Disabled
+ EnableFastChecks
+ %(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+ Level3
+ %(AdditionalIncludeDirectories);..\..\..\addons\ofxJSON\libs;..\..\..\addons\ofxJSON\libs\jsoncpp;..\..\..\addons\ofxJSON\libs\jsoncpp\include;..\..\..\addons\ofxJSON\libs\jsoncpp\include\json;..\..\..\addons\ofxJSON\libs\jsoncpp\src;..\..\..\addons\ofxJSON\src
+ CompileAsCpp
+ true
+ $(IntDir)%(RelativeDir)
+
+
+ true
+ Console
+ false
+ %(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+
+
+
+
+
+ false
+ %(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level3
+ %(AdditionalIncludeDirectories);..\..\..\addons\ofxJSON\libs;..\..\..\addons\ofxJSON\libs\jsoncpp;..\..\..\addons\ofxJSON\libs\jsoncpp\include;..\..\..\addons\ofxJSON\libs\jsoncpp\include\json;..\..\..\addons\ofxJSON\libs\jsoncpp\src;..\..\..\addons\ofxJSON\src
+ CompileAsCpp
+ true
+ $(IntDir)%(RelativeDir)
+
+
+ false
+ false
+ Console
+ true
+ true
+ false
+ %(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+
+
+
+
+
+ false
+ %(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level3
+ %(AdditionalIncludeDirectories);..\..\..\addons\ofxJSON\libs;..\..\..\addons\ofxJSON\libs\jsoncpp;..\..\..\addons\ofxJSON\libs\jsoncpp\include;..\..\..\addons\ofxJSON\libs\jsoncpp\include\json;..\..\..\addons\ofxJSON\libs\jsoncpp\src;..\..\..\addons\ofxJSON\src
+ CompileAsCpp
+ $(IntDir)%(RelativeDir)
+
+
+ false
+ false
+ Console
+ true
+ true
+ false
+ %(AdditionalDependencies)
+ %(AdditionalLibraryDirectories)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {5837595d-aca9-485c-8e76-729040ce4b0b}
+
+
+
+
+ /D_DEBUG %(AdditionalOptions)
+ /D_DEBUG %(AdditionalOptions)
+ $(OF_ROOT)\libs\openFrameworksCompiled\project\vs
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SlidePlayer/SlidePlayer.vcxproj.filters b/SlidePlayer/SlidePlayer.vcxproj.filters
new file mode 100644
index 0000000..99443a2
--- /dev/null
+++ b/SlidePlayer/SlidePlayer.vcxproj.filters
@@ -0,0 +1,66 @@
+
+
+
+
+ src
+
+
+ src
+
+
+ addons\ofxJSON\src
+
+
+ addons\ofxJSON\libs\jsoncpp\src
+
+
+
+
+ {d8376475-7454-4a24-b08a-aac121d3ad6f}
+
+
+ {71834F65-F3A9-211E-73B8-DC85}
+
+
+ {CF86E01B-D8D7-A112-88F3-5883}
+
+
+ {CE83AFE9-FE4A-682E-D5C9-50B4}
+
+
+ {5302B3F8-ECDD-0465-334A-F39E}
+
+
+ {87D6C548-39D9-FD9F-093E-9F4E}
+
+
+ {0B6CA981-484E-6E8C-776C-7298}
+
+
+ {5FF260B2-1497-3EFE-19D5-40DB}
+
+
+ {6D569A5B-6719-AEFD-C08E-5CE5}
+
+
+
+
+ src
+
+
+ addons\ofxJSON\src
+
+
+ addons\ofxJSON\src
+
+
+ addons\ofxJSON\libs\jsoncpp\include\json
+
+
+ addons\ofxJSON\libs\jsoncpp\include\json
+
+
+
+
+
+
diff --git a/SlidePlayer/SlidePlayer.xcodeproj/project.pbxproj b/SlidePlayer/SlidePlayer.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..e7e1a76
--- /dev/null
+++ b/SlidePlayer/SlidePlayer.xcodeproj/project.pbxproj
@@ -0,0 +1,990 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 8EF01BA52F7876C700BF0971 /* emotibitSlidePlayerSettings.json in Copy Settings and Example Slides */ = {isa = PBXBuildFile; fileRef = 8EF01BA42F7876C700BF0971 /* emotibitSlidePlayerSettings.json */; };
+ 8EF01BA72F7876DD00BF0971 /* example_slides in Copy Settings and Example Slides */ = {isa = PBXBuildFile; fileRef = 8EF01BA62F7876DD00BF0971 /* example_slides */; };
+ BEDFEE7400C58EA4E412B757 /* ofxJSONElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F2B099E6BD1199664C48B177 /* ofxJSONElement.cpp */; };
+ E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4B69E1D0A3A1BDC003C02F2 /* main.cpp */; };
+ E4B69E210A3A1BDC003C02F2 /* ofApp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */; };
+ FB84AAF8D1B7A95266DB5C09 /* jsoncpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21BDE665988474F1B1F4D302 /* jsoncpp.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8EF01BA32F78768F00BF0971 /* Copy Settings and Example Slides */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 7;
+ files = (
+ 8EF01BA72F7876DD00BF0971 /* example_slides in Copy Settings and Example Slides */,
+ 8EF01BA52F7876C700BF0971 /* emotibitSlidePlayerSettings.json in Copy Settings and Example Slides */,
+ );
+ name = "Copy Settings and Example Slides";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ E4C2427710CC5ABF004149E2 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1645F56257269CD0356320BD /* ofxJSON.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = ofxJSON.h; path = ../../../addons/ofxJSON/src/ofxJSON.h; sourceTree = SOURCE_ROOT; };
+ 21BDE665988474F1B1F4D302 /* jsoncpp.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = jsoncpp.cpp; path = ../../../addons/ofxJSON/libs/jsoncpp/src/jsoncpp.cpp; sourceTree = SOURCE_ROOT; };
+ 26A541233BC6F736E758F718 /* ofxJSONElement.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = ofxJSONElement.h; path = ../../../addons/ofxJSON/src/ofxJSONElement.h; sourceTree = SOURCE_ROOT; };
+ 2C7CF000B7B4F782C187C353 /* json.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = json.h; path = ../../../addons/ofxJSON/libs/jsoncpp/include/json/json.h; sourceTree = SOURCE_ROOT; };
+ 61313493CDB52744E22A604D /* json-forwards.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = "json-forwards.h"; path = "../../../addons/ofxJSON/libs/jsoncpp/include/json/json-forwards.h"; sourceTree = SOURCE_ROOT; };
+ 8EF01BA42F7876C700BF0971 /* emotibitSlidePlayerSettings.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = emotibitSlidePlayerSettings.json; path = bin/data/emotibitSlidePlayerSettings.json; sourceTree = ""; };
+ 8EF01BA62F7876DD00BF0971 /* example_slides */ = {isa = PBXFileReference; lastKnownFileType = folder; name = example_slides; path = bin/data/example_slides; sourceTree = ""; };
+ E42962AC2163EDD300A6A9E2 /* ofCamera.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofCamera.cpp; path = ../../../libs/openFrameworks/3d/ofCamera.cpp; sourceTree = SOURCE_ROOT; };
+ E42962AD2163EDD300A6A9E2 /* ofMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMesh.h; path = ../../../libs/openFrameworks/3d/ofMesh.h; sourceTree = SOURCE_ROOT; };
+ E42962AE2163EDD300A6A9E2 /* ofNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofNode.h; path = ../../../libs/openFrameworks/3d/ofNode.h; sourceTree = SOURCE_ROOT; };
+ E42962AF2163EDD300A6A9E2 /* ofNode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofNode.cpp; path = ../../../libs/openFrameworks/3d/ofNode.cpp; sourceTree = SOURCE_ROOT; };
+ E42962B02163EDD300A6A9E2 /* of3dPrimitives.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = of3dPrimitives.cpp; path = ../../../libs/openFrameworks/3d/of3dPrimitives.cpp; sourceTree = SOURCE_ROOT; };
+ E42962B12163EDD300A6A9E2 /* of3dUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = of3dUtils.h; path = ../../../libs/openFrameworks/3d/of3dUtils.h; sourceTree = SOURCE_ROOT; };
+ E42962B22163EDD300A6A9E2 /* ofEasyCam.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofEasyCam.cpp; path = ../../../libs/openFrameworks/3d/ofEasyCam.cpp; sourceTree = SOURCE_ROOT; };
+ E42962B32163EDD300A6A9E2 /* ofCamera.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofCamera.h; path = ../../../libs/openFrameworks/3d/ofCamera.h; sourceTree = SOURCE_ROOT; };
+ E42962B42163EDD300A6A9E2 /* ofMesh.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = ofMesh.inl; path = ../../../libs/openFrameworks/3d/ofMesh.inl; sourceTree = SOURCE_ROOT; };
+ E42962B52163EDD300A6A9E2 /* of3dUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = of3dUtils.cpp; path = ../../../libs/openFrameworks/3d/of3dUtils.cpp; sourceTree = SOURCE_ROOT; };
+ E42962B62163EDD300A6A9E2 /* of3dPrimitives.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = of3dPrimitives.h; path = ../../../libs/openFrameworks/3d/of3dPrimitives.h; sourceTree = SOURCE_ROOT; };
+ E42962B72163EDD300A6A9E2 /* ofEasyCam.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofEasyCam.h; path = ../../../libs/openFrameworks/3d/ofEasyCam.h; sourceTree = SOURCE_ROOT; };
+ E42962BA2163EDD300A6A9E2 /* ofAVFoundationGrabber.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAVFoundationGrabber.h; path = ../../../libs/openFrameworks/video/ofAVFoundationGrabber.h; sourceTree = SOURCE_ROOT; };
+ E42962BB2163EDD300A6A9E2 /* ofVideoPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVideoPlayer.h; path = ../../../libs/openFrameworks/video/ofVideoPlayer.h; sourceTree = SOURCE_ROOT; };
+ E42962BC2163EDD300A6A9E2 /* ofAVFoundationPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAVFoundationPlayer.h; path = ../../../libs/openFrameworks/video/ofAVFoundationPlayer.h; sourceTree = SOURCE_ROOT; };
+ E42962BD2163EDD300A6A9E2 /* ofQtUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofQtUtils.cpp; path = ../../../libs/openFrameworks/video/ofQtUtils.cpp; sourceTree = SOURCE_ROOT; };
+ E42962BE2163EDD300A6A9E2 /* ofQTKitGrabber.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ofQTKitGrabber.mm; path = ../../../libs/openFrameworks/video/ofQTKitGrabber.mm; sourceTree = SOURCE_ROOT; };
+ E42962BF2163EDD300A6A9E2 /* ofQuickTimeGrabber.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofQuickTimeGrabber.cpp; path = ../../../libs/openFrameworks/video/ofQuickTimeGrabber.cpp; sourceTree = SOURCE_ROOT; };
+ E42962C12163EDD300A6A9E2 /* ofAVFoundationVideoPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAVFoundationVideoPlayer.h; path = ../../../libs/openFrameworks/video/ofAVFoundationVideoPlayer.h; sourceTree = SOURCE_ROOT; };
+ E42962C22163EDD300A6A9E2 /* ofAVFoundationGrabber.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ofAVFoundationGrabber.mm; path = ../../../libs/openFrameworks/video/ofAVFoundationGrabber.mm; sourceTree = SOURCE_ROOT; };
+ E42962C32163EDD300A6A9E2 /* ofQTKitMovieRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofQTKitMovieRenderer.h; path = ../../../libs/openFrameworks/video/ofQTKitMovieRenderer.h; sourceTree = SOURCE_ROOT; };
+ E42962C42163EDD300A6A9E2 /* ofVideoPlayer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofVideoPlayer.cpp; path = ../../../libs/openFrameworks/video/ofVideoPlayer.cpp; sourceTree = SOURCE_ROOT; };
+ E42962C52163EDD300A6A9E2 /* ofQTKitGrabber.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofQTKitGrabber.h; path = ../../../libs/openFrameworks/video/ofQTKitGrabber.h; sourceTree = SOURCE_ROOT; };
+ E42962C72163EDD300A6A9E2 /* ofQuickTimeGrabber.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofQuickTimeGrabber.h; path = ../../../libs/openFrameworks/video/ofQuickTimeGrabber.h; sourceTree = SOURCE_ROOT; };
+ E42962C92163EDD300A6A9E2 /* ofQuickTimePlayer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofQuickTimePlayer.cpp; path = ../../../libs/openFrameworks/video/ofQuickTimePlayer.cpp; sourceTree = SOURCE_ROOT; };
+ E42962CA2163EDD300A6A9E2 /* ofVideoGrabber.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVideoGrabber.h; path = ../../../libs/openFrameworks/video/ofVideoGrabber.h; sourceTree = SOURCE_ROOT; };
+ E42962CB2163EDD300A6A9E2 /* ofQTKitPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofQTKitPlayer.h; path = ../../../libs/openFrameworks/video/ofQTKitPlayer.h; sourceTree = SOURCE_ROOT; };
+ E42962CD2163EDD300A6A9E2 /* ofQtUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofQtUtils.h; path = ../../../libs/openFrameworks/video/ofQtUtils.h; sourceTree = SOURCE_ROOT; };
+ E42962CE2163EDD300A6A9E2 /* ofAVFoundationPlayer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ofAVFoundationPlayer.mm; path = ../../../libs/openFrameworks/video/ofAVFoundationPlayer.mm; sourceTree = SOURCE_ROOT; };
+ E42962CF2163EDD300A6A9E2 /* ofQuickTimePlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofQuickTimePlayer.h; path = ../../../libs/openFrameworks/video/ofQuickTimePlayer.h; sourceTree = SOURCE_ROOT; };
+ E42962D02163EDD300A6A9E2 /* ofVideoGrabber.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofVideoGrabber.cpp; path = ../../../libs/openFrameworks/video/ofVideoGrabber.cpp; sourceTree = SOURCE_ROOT; };
+ E42962D52163EDD300A6A9E2 /* ofQTKitPlayer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ofQTKitPlayer.mm; path = ../../../libs/openFrameworks/video/ofQTKitPlayer.mm; sourceTree = SOURCE_ROOT; };
+ E42962D62163EDD300A6A9E2 /* ofQTKitMovieRenderer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ofQTKitMovieRenderer.m; path = ../../../libs/openFrameworks/video/ofQTKitMovieRenderer.m; sourceTree = SOURCE_ROOT; };
+ E42962D72163EDD300A6A9E2 /* ofAVFoundationVideoPlayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ofAVFoundationVideoPlayer.m; path = ../../../libs/openFrameworks/video/ofAVFoundationVideoPlayer.m; sourceTree = SOURCE_ROOT; };
+ E42962D92163EDD300A6A9E2 /* ofVideoBaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVideoBaseTypes.h; path = ../../../libs/openFrameworks/video/ofVideoBaseTypes.h; sourceTree = SOURCE_ROOT; };
+ E42962DB2163EDD300A6A9E2 /* ofParameterGroup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofParameterGroup.h; path = ../../../libs/openFrameworks/types/ofParameterGroup.h; sourceTree = SOURCE_ROOT; };
+ E42962DC2163EDD300A6A9E2 /* ofColor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofColor.h; path = ../../../libs/openFrameworks/types/ofColor.h; sourceTree = SOURCE_ROOT; };
+ E42962DD2163EDD300A6A9E2 /* ofRectangle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofRectangle.cpp; path = ../../../libs/openFrameworks/types/ofRectangle.cpp; sourceTree = SOURCE_ROOT; };
+ E42962DE2163EDD300A6A9E2 /* ofPoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofPoint.h; path = ../../../libs/openFrameworks/types/ofPoint.h; sourceTree = SOURCE_ROOT; };
+ E42962DF2163EDD300A6A9E2 /* ofTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofTypes.h; path = ../../../libs/openFrameworks/types/ofTypes.h; sourceTree = SOURCE_ROOT; };
+ E42962E02163EDD300A6A9E2 /* ofRectangle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofRectangle.h; path = ../../../libs/openFrameworks/types/ofRectangle.h; sourceTree = SOURCE_ROOT; };
+ E42962E12163EDD300A6A9E2 /* ofBaseTypes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofBaseTypes.cpp; path = ../../../libs/openFrameworks/types/ofBaseTypes.cpp; sourceTree = SOURCE_ROOT; };
+ E42962E22163EDD300A6A9E2 /* ofParameterGroup.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofParameterGroup.cpp; path = ../../../libs/openFrameworks/types/ofParameterGroup.cpp; sourceTree = SOURCE_ROOT; };
+ E42962E32163EDD300A6A9E2 /* ofParameter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofParameter.h; path = ../../../libs/openFrameworks/types/ofParameter.h; sourceTree = SOURCE_ROOT; };
+ E42962E42163EDD300A6A9E2 /* ofColor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofColor.cpp; path = ../../../libs/openFrameworks/types/ofColor.cpp; sourceTree = SOURCE_ROOT; };
+ E42962E52163EDD300A6A9E2 /* ofParameter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofParameter.cpp; path = ../../../libs/openFrameworks/types/ofParameter.cpp; sourceTree = SOURCE_ROOT; };
+ E42962E62163EDD300A6A9E2 /* ofBaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofBaseTypes.h; path = ../../../libs/openFrameworks/types/ofBaseTypes.h; sourceTree = SOURCE_ROOT; };
+ E42962E82163EDD300A6A9E2 /* ofMainLoop.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMainLoop.h; path = ../../../libs/openFrameworks/app/ofMainLoop.h; sourceTree = SOURCE_ROOT; };
+ E42962E92163EDD300A6A9E2 /* ofBaseApp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofBaseApp.cpp; path = ../../../libs/openFrameworks/app/ofBaseApp.cpp; sourceTree = SOURCE_ROOT; };
+ E42962EA2163EDD300A6A9E2 /* ofAppGlutWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofAppGlutWindow.cpp; path = ../../../libs/openFrameworks/app/ofAppGlutWindow.cpp; sourceTree = SOURCE_ROOT; };
+ E42962EB2163EDD300A6A9E2 /* ofWindowSettings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofWindowSettings.h; path = ../../../libs/openFrameworks/app/ofWindowSettings.h; sourceTree = SOURCE_ROOT; };
+ E42962EC2163EDD300A6A9E2 /* ofAppEGLWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofAppEGLWindow.cpp; path = ../../../libs/openFrameworks/app/ofAppEGLWindow.cpp; sourceTree = SOURCE_ROOT; };
+ E42962ED2163EDD300A6A9E2 /* ofAppBaseWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAppBaseWindow.h; path = ../../../libs/openFrameworks/app/ofAppBaseWindow.h; sourceTree = SOURCE_ROOT; };
+ E42962EE2163EDD300A6A9E2 /* ofIcon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofIcon.h; path = ../../../libs/openFrameworks/app/ofIcon.h; sourceTree = SOURCE_ROOT; };
+ E42962EF2163EDD300A6A9E2 /* ofAppNoWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAppNoWindow.h; path = ../../../libs/openFrameworks/app/ofAppNoWindow.h; sourceTree = SOURCE_ROOT; };
+ E42962F02163EDD300A6A9E2 /* ofBaseApp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofBaseApp.h; path = ../../../libs/openFrameworks/app/ofBaseApp.h; sourceTree = SOURCE_ROOT; };
+ E42962F12163EDD300A6A9E2 /* ofAppEGLWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAppEGLWindow.h; path = ../../../libs/openFrameworks/app/ofAppEGLWindow.h; sourceTree = SOURCE_ROOT; };
+ E42962F22163EDD300A6A9E2 /* ofMainLoop.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofMainLoop.cpp; path = ../../../libs/openFrameworks/app/ofMainLoop.cpp; sourceTree = SOURCE_ROOT; };
+ E42962F32163EDD300A6A9E2 /* ofAppRunner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAppRunner.h; path = ../../../libs/openFrameworks/app/ofAppRunner.h; sourceTree = SOURCE_ROOT; };
+ E42962F42163EDD300A6A9E2 /* ofAppNoWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofAppNoWindow.cpp; path = ../../../libs/openFrameworks/app/ofAppNoWindow.cpp; sourceTree = SOURCE_ROOT; };
+ E42962F52163EDD300A6A9E2 /* ofAppGLFWWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofAppGLFWWindow.cpp; path = ../../../libs/openFrameworks/app/ofAppGLFWWindow.cpp; sourceTree = SOURCE_ROOT; };
+ E42962F62163EDD300A6A9E2 /* ofAppGlutWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAppGlutWindow.h; path = ../../../libs/openFrameworks/app/ofAppGlutWindow.h; sourceTree = SOURCE_ROOT; };
+ E42962F72163EDD300A6A9E2 /* ofAppRunner.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofAppRunner.cpp; path = ../../../libs/openFrameworks/app/ofAppRunner.cpp; sourceTree = SOURCE_ROOT; };
+ E42962F82163EDD300A6A9E2 /* ofAppGLFWWindow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofAppGLFWWindow.h; path = ../../../libs/openFrameworks/app/ofAppGLFWWindow.h; sourceTree = SOURCE_ROOT; };
+ E42962F92163EDD300A6A9E2 /* ofMain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMain.h; path = ../../../libs/openFrameworks/ofMain.h; sourceTree = SOURCE_ROOT; };
+ E42962FB2163EDD300A6A9E2 /* ofThreadChannel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofThreadChannel.h; path = ../../../libs/openFrameworks/utils/ofThreadChannel.h; sourceTree = SOURCE_ROOT; };
+ E42962FC2163EDD300A6A9E2 /* ofThread.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofThread.cpp; path = ../../../libs/openFrameworks/utils/ofThread.cpp; sourceTree = SOURCE_ROOT; };
+ E42962FD2163EDD300A6A9E2 /* ofFpsCounter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofFpsCounter.cpp; path = ../../../libs/openFrameworks/utils/ofFpsCounter.cpp; sourceTree = SOURCE_ROOT; };
+ E42962FE2163EDD300A6A9E2 /* ofURLFileLoader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofURLFileLoader.cpp; path = ../../../libs/openFrameworks/utils/ofURLFileLoader.cpp; sourceTree = SOURCE_ROOT; };
+ E42962FF2163EDD300A6A9E2 /* ofConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofConstants.h; path = ../../../libs/openFrameworks/utils/ofConstants.h; sourceTree = SOURCE_ROOT; };
+ E42963002163EDD300A6A9E2 /* ofXml.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofXml.h; path = ../../../libs/openFrameworks/utils/ofXml.h; sourceTree = SOURCE_ROOT; };
+ E42963012163EDD300A6A9E2 /* ofFpsCounter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofFpsCounter.h; path = ../../../libs/openFrameworks/utils/ofFpsCounter.h; sourceTree = SOURCE_ROOT; };
+ E42963022163EDD300A6A9E2 /* ofLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofLog.h; path = ../../../libs/openFrameworks/utils/ofLog.h; sourceTree = SOURCE_ROOT; };
+ E42963032163EDD300A6A9E2 /* ofSystemUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofSystemUtils.h; path = ../../../libs/openFrameworks/utils/ofSystemUtils.h; sourceTree = SOURCE_ROOT; };
+ E42963042163EDD300A6A9E2 /* ofSystemUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofSystemUtils.cpp; path = ../../../libs/openFrameworks/utils/ofSystemUtils.cpp; sourceTree = SOURCE_ROOT; };
+ E42963052163EDD300A6A9E2 /* ofUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofUtils.h; path = ../../../libs/openFrameworks/utils/ofUtils.h; sourceTree = SOURCE_ROOT; };
+ E42963062163EDD300A6A9E2 /* ofNoise.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofNoise.h; path = ../../../libs/openFrameworks/utils/ofNoise.h; sourceTree = SOURCE_ROOT; };
+ E42963072163EDD300A6A9E2 /* ofLog.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofLog.cpp; path = ../../../libs/openFrameworks/utils/ofLog.cpp; sourceTree = SOURCE_ROOT; };
+ E42963082163EDD300A6A9E2 /* ofTimer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofTimer.cpp; path = ../../../libs/openFrameworks/utils/ofTimer.cpp; sourceTree = SOURCE_ROOT; };
+ E42963092163EDD300A6A9E2 /* ofFileUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofFileUtils.h; path = ../../../libs/openFrameworks/utils/ofFileUtils.h; sourceTree = SOURCE_ROOT; };
+ E429630A2163EDD300A6A9E2 /* ofThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofThread.h; path = ../../../libs/openFrameworks/utils/ofThread.h; sourceTree = SOURCE_ROOT; };
+ E429630B2163EDD300A6A9E2 /* ofURLFileLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofURLFileLoader.h; path = ../../../libs/openFrameworks/utils/ofURLFileLoader.h; sourceTree = SOURCE_ROOT; };
+ E429630C2163EDD300A6A9E2 /* ofJson.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofJson.h; path = ../../../libs/openFrameworks/utils/ofJson.h; sourceTree = SOURCE_ROOT; };
+ E429630D2163EDD300A6A9E2 /* ofFileUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofFileUtils.cpp; path = ../../../libs/openFrameworks/utils/ofFileUtils.cpp; sourceTree = SOURCE_ROOT; };
+ E429630E2163EDD300A6A9E2 /* ofMatrixStack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofMatrixStack.cpp; path = ../../../libs/openFrameworks/utils/ofMatrixStack.cpp; sourceTree = SOURCE_ROOT; };
+ E429630F2163EDD300A6A9E2 /* ofUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofUtils.cpp; path = ../../../libs/openFrameworks/utils/ofUtils.cpp; sourceTree = SOURCE_ROOT; };
+ E42963102163EDD300A6A9E2 /* ofXml.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofXml.cpp; path = ../../../libs/openFrameworks/utils/ofXml.cpp; sourceTree = SOURCE_ROOT; };
+ E42963112163EDD300A6A9E2 /* ofMatrixStack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMatrixStack.h; path = ../../../libs/openFrameworks/utils/ofMatrixStack.h; sourceTree = SOURCE_ROOT; };
+ E42963122163EDD300A6A9E2 /* ofTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofTimer.h; path = ../../../libs/openFrameworks/utils/ofTimer.h; sourceTree = SOURCE_ROOT; };
+ E42963142163EDD300A6A9E2 /* ofVec2f.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofVec2f.cpp; path = ../../../libs/openFrameworks/math/ofVec2f.cpp; sourceTree = SOURCE_ROOT; };
+ E42963152163EDD300A6A9E2 /* ofVec4f.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofVec4f.cpp; path = ../../../libs/openFrameworks/math/ofVec4f.cpp; sourceTree = SOURCE_ROOT; };
+ E42963162163EDD300A6A9E2 /* ofVec4f.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVec4f.h; path = ../../../libs/openFrameworks/math/ofVec4f.h; sourceTree = SOURCE_ROOT; };
+ E42963172163EDD300A6A9E2 /* ofMath.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofMath.cpp; path = ../../../libs/openFrameworks/math/ofMath.cpp; sourceTree = SOURCE_ROOT; };
+ E42963182163EDD300A6A9E2 /* ofMathConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMathConstants.h; path = ../../../libs/openFrameworks/math/ofMathConstants.h; sourceTree = SOURCE_ROOT; };
+ E42963192163EDD300A6A9E2 /* ofMatrix4x4.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMatrix4x4.h; path = ../../../libs/openFrameworks/math/ofMatrix4x4.h; sourceTree = SOURCE_ROOT; };
+ E429631A2163EDD300A6A9E2 /* ofVec3f.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVec3f.h; path = ../../../libs/openFrameworks/math/ofVec3f.h; sourceTree = SOURCE_ROOT; };
+ E429631B2163EDD300A6A9E2 /* ofMatrix3x3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofMatrix3x3.cpp; path = ../../../libs/openFrameworks/math/ofMatrix3x3.cpp; sourceTree = SOURCE_ROOT; };
+ E429631C2163EDD300A6A9E2 /* ofMath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMath.h; path = ../../../libs/openFrameworks/math/ofMath.h; sourceTree = SOURCE_ROOT; };
+ E429631D2163EDD300A6A9E2 /* ofQuaternion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofQuaternion.h; path = ../../../libs/openFrameworks/math/ofQuaternion.h; sourceTree = SOURCE_ROOT; };
+ E429631E2163EDD300A6A9E2 /* ofVectorMath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVectorMath.h; path = ../../../libs/openFrameworks/math/ofVectorMath.h; sourceTree = SOURCE_ROOT; };
+ E429631F2163EDD300A6A9E2 /* ofQuaternion.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofQuaternion.cpp; path = ../../../libs/openFrameworks/math/ofQuaternion.cpp; sourceTree = SOURCE_ROOT; };
+ E42963202163EDD300A6A9E2 /* ofVec2f.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVec2f.h; path = ../../../libs/openFrameworks/math/ofVec2f.h; sourceTree = SOURCE_ROOT; };
+ E42963212163EDD300A6A9E2 /* ofMatrix4x4.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofMatrix4x4.cpp; path = ../../../libs/openFrameworks/math/ofMatrix4x4.cpp; sourceTree = SOURCE_ROOT; };
+ E42963222163EDD300A6A9E2 /* ofMatrix3x3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMatrix3x3.h; path = ../../../libs/openFrameworks/math/ofMatrix3x3.h; sourceTree = SOURCE_ROOT; };
+ E42963262163EDD300A6A9E2 /* ofVboMesh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVboMesh.h; path = ../../../libs/openFrameworks/gl/ofVboMesh.h; sourceTree = SOURCE_ROOT; };
+ E42963272163EDD300A6A9E2 /* ofTexture.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofTexture.h; path = ../../../libs/openFrameworks/gl/ofTexture.h; sourceTree = SOURCE_ROOT; };
+ E42963282163EDD300A6A9E2 /* ofShader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofShader.h; path = ../../../libs/openFrameworks/gl/ofShader.h; sourceTree = SOURCE_ROOT; };
+ E42963292163EDD300A6A9E2 /* ofMaterial.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofMaterial.cpp; path = ../../../libs/openFrameworks/gl/ofMaterial.cpp; sourceTree = SOURCE_ROOT; };
+ E429632A2163EDD300A6A9E2 /* ofFbo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofFbo.cpp; path = ../../../libs/openFrameworks/gl/ofFbo.cpp; sourceTree = SOURCE_ROOT; };
+ E429632B2163EDD300A6A9E2 /* ofLight.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofLight.h; path = ../../../libs/openFrameworks/gl/ofLight.h; sourceTree = SOURCE_ROOT; };
+ E429632C2163EDD300A6A9E2 /* ofMaterial.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofMaterial.h; path = ../../../libs/openFrameworks/gl/ofMaterial.h; sourceTree = SOURCE_ROOT; };
+ E429632D2163EDD300A6A9E2 /* ofShader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofShader.cpp; path = ../../../libs/openFrameworks/gl/ofShader.cpp; sourceTree = SOURCE_ROOT; };
+ E429632E2163EDD300A6A9E2 /* ofBufferObject.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofBufferObject.cpp; path = ../../../libs/openFrameworks/gl/ofBufferObject.cpp; sourceTree = SOURCE_ROOT; };
+ E429632F2163EDD300A6A9E2 /* ofVboMesh.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofVboMesh.cpp; path = ../../../libs/openFrameworks/gl/ofVboMesh.cpp; sourceTree = SOURCE_ROOT; };
+ E42963302163EDD300A6A9E2 /* ofGLUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofGLUtils.cpp; path = ../../../libs/openFrameworks/gl/ofGLUtils.cpp; sourceTree = SOURCE_ROOT; };
+ E42963312163EDD300A6A9E2 /* ofVbo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofVbo.h; path = ../../../libs/openFrameworks/gl/ofVbo.h; sourceTree = SOURCE_ROOT; };
+ E42963322163EDD300A6A9E2 /* ofLight.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofLight.cpp; path = ../../../libs/openFrameworks/gl/ofLight.cpp; sourceTree = SOURCE_ROOT; };
+ E42963332163EDD300A6A9E2 /* ofBufferObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofBufferObject.h; path = ../../../libs/openFrameworks/gl/ofBufferObject.h; sourceTree = SOURCE_ROOT; };
+ E42963342163EDD300A6A9E2 /* ofGLProgrammableRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofGLProgrammableRenderer.cpp; path = ../../../libs/openFrameworks/gl/ofGLProgrammableRenderer.cpp; sourceTree = SOURCE_ROOT; };
+ E42963382163EDD300A6A9E2 /* ofFbo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofFbo.h; path = ../../../libs/openFrameworks/gl/ofFbo.h; sourceTree = SOURCE_ROOT; };
+ E42963392163EDD300A6A9E2 /* ofGLBaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofGLBaseTypes.h; path = ../../../libs/openFrameworks/gl/ofGLBaseTypes.h; sourceTree = SOURCE_ROOT; };
+ E429633A2163EDD300A6A9E2 /* ofVbo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofVbo.cpp; path = ../../../libs/openFrameworks/gl/ofVbo.cpp; sourceTree = SOURCE_ROOT; };
+ E429633B2163EDD300A6A9E2 /* ofGLProgrammableRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofGLProgrammableRenderer.h; path = ../../../libs/openFrameworks/gl/ofGLProgrammableRenderer.h; sourceTree = SOURCE_ROOT; };
+ E429633C2163EDD300A6A9E2 /* ofTexture.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofTexture.cpp; path = ../../../libs/openFrameworks/gl/ofTexture.cpp; sourceTree = SOURCE_ROOT; };
+ E429633D2163EDD300A6A9E2 /* ofGLUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofGLUtils.h; path = ../../../libs/openFrameworks/gl/ofGLUtils.h; sourceTree = SOURCE_ROOT; };
+ E429633E2163EDD300A6A9E2 /* ofGLRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofGLRenderer.cpp; path = ../../../libs/openFrameworks/gl/ofGLRenderer.cpp; sourceTree = SOURCE_ROOT; };
+ E429633F2163EDD300A6A9E2 /* ofGLRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofGLRenderer.h; path = ../../../libs/openFrameworks/gl/ofGLRenderer.h; sourceTree = SOURCE_ROOT; };
+ E42963412163EDD300A6A9E2 /* ofArduino.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofArduino.h; path = ../../../libs/openFrameworks/communication/ofArduino.h; sourceTree = SOURCE_ROOT; };
+ E42963422163EDD300A6A9E2 /* ofSerial.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofSerial.cpp; path = ../../../libs/openFrameworks/communication/ofSerial.cpp; sourceTree = SOURCE_ROOT; };
+ E42963432163EDD300A6A9E2 /* ofSerial.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofSerial.h; path = ../../../libs/openFrameworks/communication/ofSerial.h; sourceTree = SOURCE_ROOT; };
+ E42963442163EDD300A6A9E2 /* ofArduino.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofArduino.cpp; path = ../../../libs/openFrameworks/communication/ofArduino.cpp; sourceTree = SOURCE_ROOT; };
+ E42963462163EDD300A6A9E2 /* ofEventUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofEventUtils.h; path = ../../../libs/openFrameworks/events/ofEventUtils.h; sourceTree = SOURCE_ROOT; };
+ E42963472163EDD300A6A9E2 /* ofEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofEvent.h; path = ../../../libs/openFrameworks/events/ofEvent.h; sourceTree = SOURCE_ROOT; };
+ E42963482163EDD300A6A9E2 /* ofEvents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofEvents.h; path = ../../../libs/openFrameworks/events/ofEvents.h; sourceTree = SOURCE_ROOT; };
+ E42963492163EDD300A6A9E2 /* ofEvents.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofEvents.cpp; path = ../../../libs/openFrameworks/events/ofEvents.cpp; sourceTree = SOURCE_ROOT; };
+ E429634B2163EDD300A6A9E2 /* ofGraphicsBaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofGraphicsBaseTypes.h; path = ../../../libs/openFrameworks/graphics/ofGraphicsBaseTypes.h; sourceTree = SOURCE_ROOT; };
+ E429634C2163EDD300A6A9E2 /* ofPath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofPath.h; path = ../../../libs/openFrameworks/graphics/ofPath.h; sourceTree = SOURCE_ROOT; };
+ E429634D2163EDD300A6A9E2 /* ofBitmapFont.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofBitmapFont.cpp; path = ../../../libs/openFrameworks/graphics/ofBitmapFont.cpp; sourceTree = SOURCE_ROOT; };
+ E429634E2163EDD300A6A9E2 /* ofTrueTypeFont.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofTrueTypeFont.h; path = ../../../libs/openFrameworks/graphics/ofTrueTypeFont.h; sourceTree = SOURCE_ROOT; };
+ E429634F2163EDD300A6A9E2 /* ofTessellator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofTessellator.cpp; path = ../../../libs/openFrameworks/graphics/ofTessellator.cpp; sourceTree = SOURCE_ROOT; };
+ E42963502163EDD300A6A9E2 /* ofGraphics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofGraphics.cpp; path = ../../../libs/openFrameworks/graphics/ofGraphics.cpp; sourceTree = SOURCE_ROOT; };
+ E42963512163EDD300A6A9E2 /* ofPolyline.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofPolyline.h; path = ../../../libs/openFrameworks/graphics/ofPolyline.h; sourceTree = SOURCE_ROOT; };
+ E42963522163EDD300A6A9E2 /* ofGraphicsBaseTypes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofGraphicsBaseTypes.cpp; path = ../../../libs/openFrameworks/graphics/ofGraphicsBaseTypes.cpp; sourceTree = SOURCE_ROOT; };
+ E42963532163EDD300A6A9E2 /* ofCairoRenderer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofCairoRenderer.cpp; path = ../../../libs/openFrameworks/graphics/ofCairoRenderer.cpp; sourceTree = SOURCE_ROOT; };
+ E42963542163EDD300A6A9E2 /* ofRendererCollection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofRendererCollection.cpp; path = ../../../libs/openFrameworks/graphics/ofRendererCollection.cpp; sourceTree = SOURCE_ROOT; };
+ E42963552163EDD300A6A9E2 /* ofPath.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofPath.cpp; path = ../../../libs/openFrameworks/graphics/ofPath.cpp; sourceTree = SOURCE_ROOT; };
+ E42963562163EDD300A6A9E2 /* ofPixels.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofPixels.cpp; path = ../../../libs/openFrameworks/graphics/ofPixels.cpp; sourceTree = SOURCE_ROOT; };
+ E42963572163EDD300A6A9E2 /* ofPolyline.inl */ = {isa = PBXFileReference; lastKnownFileType = text; name = ofPolyline.inl; path = ../../../libs/openFrameworks/graphics/ofPolyline.inl; sourceTree = SOURCE_ROOT; };
+ E42963582163EDD300A6A9E2 /* of3dGraphics.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = of3dGraphics.cpp; path = ../../../libs/openFrameworks/graphics/of3dGraphics.cpp; sourceTree = SOURCE_ROOT; };
+ E42963592163EDD300A6A9E2 /* ofImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofImage.h; path = ../../../libs/openFrameworks/graphics/ofImage.h; sourceTree = SOURCE_ROOT; };
+ E429635A2163EDD300A6A9E2 /* ofPixels.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofPixels.h; path = ../../../libs/openFrameworks/graphics/ofPixels.h; sourceTree = SOURCE_ROOT; };
+ E429635B2163EDD300A6A9E2 /* ofCairoRenderer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofCairoRenderer.h; path = ../../../libs/openFrameworks/graphics/ofCairoRenderer.h; sourceTree = SOURCE_ROOT; };
+ E429635C2163EDD300A6A9E2 /* ofBitmapFont.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofBitmapFont.h; path = ../../../libs/openFrameworks/graphics/ofBitmapFont.h; sourceTree = SOURCE_ROOT; };
+ E429635D2163EDD300A6A9E2 /* ofTrueTypeFont.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofTrueTypeFont.cpp; path = ../../../libs/openFrameworks/graphics/ofTrueTypeFont.cpp; sourceTree = SOURCE_ROOT; };
+ E429635E2163EDD300A6A9E2 /* ofRendererCollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofRendererCollection.h; path = ../../../libs/openFrameworks/graphics/ofRendererCollection.h; sourceTree = SOURCE_ROOT; };
+ E429635F2163EDD300A6A9E2 /* ofGraphics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofGraphics.h; path = ../../../libs/openFrameworks/graphics/ofGraphics.h; sourceTree = SOURCE_ROOT; };
+ E42963602163EDD300A6A9E2 /* ofGraphicsConstants.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofGraphicsConstants.h; path = ../../../libs/openFrameworks/graphics/ofGraphicsConstants.h; sourceTree = SOURCE_ROOT; };
+ E42963612163EDD300A6A9E2 /* ofImage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofImage.cpp; path = ../../../libs/openFrameworks/graphics/ofImage.cpp; sourceTree = SOURCE_ROOT; };
+ E42963622163EDD300A6A9E2 /* of3dGraphics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = of3dGraphics.h; path = ../../../libs/openFrameworks/graphics/of3dGraphics.h; sourceTree = SOURCE_ROOT; };
+ E42963632163EDD300A6A9E2 /* ofTessellator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofTessellator.h; path = ../../../libs/openFrameworks/graphics/ofTessellator.h; sourceTree = SOURCE_ROOT; };
+ E42963652163EDD300A6A9E2 /* ofSoundStream.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofSoundStream.cpp; path = ../../../libs/openFrameworks/sound/ofSoundStream.cpp; sourceTree = SOURCE_ROOT; };
+ E42963662163EDD300A6A9E2 /* ofSoundStream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofSoundStream.h; path = ../../../libs/openFrameworks/sound/ofSoundStream.h; sourceTree = SOURCE_ROOT; };
+ E42963672163EDD300A6A9E2 /* ofSoundPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofSoundPlayer.h; path = ../../../libs/openFrameworks/sound/ofSoundPlayer.h; sourceTree = SOURCE_ROOT; };
+ E42963682163EDD300A6A9E2 /* ofOpenALSoundPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofOpenALSoundPlayer.h; path = ../../../libs/openFrameworks/sound/ofOpenALSoundPlayer.h; sourceTree = SOURCE_ROOT; };
+ E42963692163EDD300A6A9E2 /* ofRtAudioSoundStream.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofRtAudioSoundStream.cpp; path = ../../../libs/openFrameworks/sound/ofRtAudioSoundStream.cpp; sourceTree = SOURCE_ROOT; };
+ E429636A2163EDD300A6A9E2 /* ofFmodSoundPlayer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofFmodSoundPlayer.cpp; path = ../../../libs/openFrameworks/sound/ofFmodSoundPlayer.cpp; sourceTree = SOURCE_ROOT; };
+ E429636B2163EDD300A6A9E2 /* ofSoundBaseTypes.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofSoundBaseTypes.cpp; path = ../../../libs/openFrameworks/sound/ofSoundBaseTypes.cpp; sourceTree = SOURCE_ROOT; };
+ E429636C2163EDD300A6A9E2 /* ofOpenALSoundPlayer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofOpenALSoundPlayer.cpp; path = ../../../libs/openFrameworks/sound/ofOpenALSoundPlayer.cpp; sourceTree = SOURCE_ROOT; };
+ E429636D2163EDD300A6A9E2 /* ofSoundPlayer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofSoundPlayer.cpp; path = ../../../libs/openFrameworks/sound/ofSoundPlayer.cpp; sourceTree = SOURCE_ROOT; };
+ E429636E2163EDD300A6A9E2 /* ofRtAudioSoundStream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofRtAudioSoundStream.h; path = ../../../libs/openFrameworks/sound/ofRtAudioSoundStream.h; sourceTree = SOURCE_ROOT; };
+ E429636F2163EDD300A6A9E2 /* ofSoundUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofSoundUtils.h; path = ../../../libs/openFrameworks/sound/ofSoundUtils.h; sourceTree = SOURCE_ROOT; };
+ E42963702163EDD300A6A9E2 /* ofSoundBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofSoundBuffer.h; path = ../../../libs/openFrameworks/sound/ofSoundBuffer.h; sourceTree = SOURCE_ROOT; };
+ E42963712163EDD300A6A9E2 /* ofFmodSoundPlayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofFmodSoundPlayer.h; path = ../../../libs/openFrameworks/sound/ofFmodSoundPlayer.h; sourceTree = SOURCE_ROOT; };
+ E42963722163EDD300A6A9E2 /* ofSoundBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = ofSoundBuffer.cpp; path = ../../../libs/openFrameworks/sound/ofSoundBuffer.cpp; sourceTree = SOURCE_ROOT; };
+ E42963732163EDD300A6A9E2 /* ofSoundBaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ofSoundBaseTypes.h; path = ../../../libs/openFrameworks/sound/ofSoundBaseTypes.h; sourceTree = SOURCE_ROOT; };
+ E4B69B5B0A3A1756003C02F2 /* SlidePlayerDebug.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SlidePlayerDebug.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ E4B69E1D0A3A1BDC003C02F2 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = src/main.cpp; sourceTree = SOURCE_ROOT; };
+ E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = ofApp.cpp; path = src/ofApp.cpp; sourceTree = SOURCE_ROOT; };
+ E4B69E1F0A3A1BDC003C02F2 /* ofApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ofApp.h; path = src/ofApp.h; sourceTree = SOURCE_ROOT; };
+ E4B6FCAD0C3E899E008CF71C /* openFrameworks-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "openFrameworks-Info.plist"; sourceTree = ""; };
+ E4EB6923138AFD0F00A09F29 /* Project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Project.xcconfig; sourceTree = ""; };
+ F2B099E6BD1199664C48B177 /* ofxJSONElement.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = ofxJSONElement.cpp; path = ../../../addons/ofxJSON/src/ofxJSONElement.cpp; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ E4B69B590A3A1756003C02F2 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2865DAEF86B1907A704CA70B /* ofxJSON */ = {
+ isa = PBXGroup;
+ children = (
+ F40E80CB2D443CBA9581DD03 /* libs */,
+ 292AF6148769654D0DF26018 /* src */,
+ );
+ name = ofxJSON;
+ sourceTree = "";
+ };
+ 292AF6148769654D0DF26018 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 1645F56257269CD0356320BD /* ofxJSON.h */,
+ F2B099E6BD1199664C48B177 /* ofxJSONElement.cpp */,
+ 26A541233BC6F736E758F718 /* ofxJSONElement.h */,
+ );
+ name = src;
+ sourceTree = "";
+ };
+ 58AD3BD71B781D9BC25763C8 /* json */ = {
+ isa = PBXGroup;
+ children = (
+ 61313493CDB52744E22A604D /* json-forwards.h */,
+ 2C7CF000B7B4F782C187C353 /* json.h */,
+ );
+ name = json;
+ sourceTree = "";
+ };
+ 6948EE371B920CB800B5AC1A /* local_addons */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = local_addons;
+ sourceTree = "";
+ };
+ 977A836DD2C489CCC5E330FF /* jsoncpp */ = {
+ isa = PBXGroup;
+ children = (
+ D486FC87F063317BB47E9FAC /* include */,
+ CCDC6F9CCF925CC402160B85 /* src */,
+ );
+ name = jsoncpp;
+ sourceTree = "";
+ };
+ BB4B014C10F69532006C3DED /* addons */ = {
+ isa = PBXGroup;
+ children = (
+ 2865DAEF86B1907A704CA70B /* ofxJSON */,
+ );
+ name = addons;
+ sourceTree = "";
+ };
+ CCDC6F9CCF925CC402160B85 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 21BDE665988474F1B1F4D302 /* jsoncpp.cpp */,
+ );
+ name = src;
+ sourceTree = "";
+ };
+ D486FC87F063317BB47E9FAC /* include */ = {
+ isa = PBXGroup;
+ children = (
+ 58AD3BD71B781D9BC25763C8 /* json */,
+ );
+ name = include;
+ sourceTree = "";
+ };
+ E42962AA2163EDD300A6A9E2 /* openFrameworks */ = {
+ isa = PBXGroup;
+ children = (
+ E42962AB2163EDD300A6A9E2 /* 3d */,
+ E42962E72163EDD300A6A9E2 /* app */,
+ E42963402163EDD300A6A9E2 /* communication */,
+ E42963452163EDD300A6A9E2 /* events */,
+ E42963252163EDD300A6A9E2 /* gl */,
+ E429634A2163EDD300A6A9E2 /* graphics */,
+ E42963132163EDD300A6A9E2 /* math */,
+ E42962F92163EDD300A6A9E2 /* ofMain.h */,
+ E42963642163EDD300A6A9E2 /* sound */,
+ E42962DA2163EDD300A6A9E2 /* types */,
+ E42962FA2163EDD300A6A9E2 /* utils */,
+ E42962B82163EDD300A6A9E2 /* video */,
+ );
+ name = openFrameworks;
+ path = ../../../libs/openFrameworks;
+ sourceTree = "";
+ };
+ E42962AB2163EDD300A6A9E2 /* 3d */ = {
+ isa = PBXGroup;
+ children = (
+ E42962B02163EDD300A6A9E2 /* of3dPrimitives.cpp */,
+ E42962B62163EDD300A6A9E2 /* of3dPrimitives.h */,
+ E42962B52163EDD300A6A9E2 /* of3dUtils.cpp */,
+ E42962B12163EDD300A6A9E2 /* of3dUtils.h */,
+ E42962AC2163EDD300A6A9E2 /* ofCamera.cpp */,
+ E42962B32163EDD300A6A9E2 /* ofCamera.h */,
+ E42962B22163EDD300A6A9E2 /* ofEasyCam.cpp */,
+ E42962B72163EDD300A6A9E2 /* ofEasyCam.h */,
+ E42962AD2163EDD300A6A9E2 /* ofMesh.h */,
+ E42962B42163EDD300A6A9E2 /* ofMesh.inl */,
+ E42962AF2163EDD300A6A9E2 /* ofNode.cpp */,
+ E42962AE2163EDD300A6A9E2 /* ofNode.h */,
+ );
+ name = 3d;
+ path = ../../../libs/openFrameworks/3d;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42962B82163EDD300A6A9E2 /* video */ = {
+ isa = PBXGroup;
+ children = (
+ E42962BA2163EDD300A6A9E2 /* ofAVFoundationGrabber.h */,
+ E42962C22163EDD300A6A9E2 /* ofAVFoundationGrabber.mm */,
+ E42962BC2163EDD300A6A9E2 /* ofAVFoundationPlayer.h */,
+ E42962CE2163EDD300A6A9E2 /* ofAVFoundationPlayer.mm */,
+ E42962C12163EDD300A6A9E2 /* ofAVFoundationVideoPlayer.h */,
+ E42962D72163EDD300A6A9E2 /* ofAVFoundationVideoPlayer.m */,
+ E42962C52163EDD300A6A9E2 /* ofQTKitGrabber.h */,
+ E42962BE2163EDD300A6A9E2 /* ofQTKitGrabber.mm */,
+ E42962C32163EDD300A6A9E2 /* ofQTKitMovieRenderer.h */,
+ E42962D62163EDD300A6A9E2 /* ofQTKitMovieRenderer.m */,
+ E42962CB2163EDD300A6A9E2 /* ofQTKitPlayer.h */,
+ E42962D52163EDD300A6A9E2 /* ofQTKitPlayer.mm */,
+ E42962BD2163EDD300A6A9E2 /* ofQtUtils.cpp */,
+ E42962CD2163EDD300A6A9E2 /* ofQtUtils.h */,
+ E42962BF2163EDD300A6A9E2 /* ofQuickTimeGrabber.cpp */,
+ E42962C72163EDD300A6A9E2 /* ofQuickTimeGrabber.h */,
+ E42962C92163EDD300A6A9E2 /* ofQuickTimePlayer.cpp */,
+ E42962CF2163EDD300A6A9E2 /* ofQuickTimePlayer.h */,
+ E42962D92163EDD300A6A9E2 /* ofVideoBaseTypes.h */,
+ E42962D02163EDD300A6A9E2 /* ofVideoGrabber.cpp */,
+ E42962CA2163EDD300A6A9E2 /* ofVideoGrabber.h */,
+ E42962C42163EDD300A6A9E2 /* ofVideoPlayer.cpp */,
+ E42962BB2163EDD300A6A9E2 /* ofVideoPlayer.h */,
+ );
+ name = video;
+ path = ../../../libs/openFrameworks/video;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42962DA2163EDD300A6A9E2 /* types */ = {
+ isa = PBXGroup;
+ children = (
+ E42962E12163EDD300A6A9E2 /* ofBaseTypes.cpp */,
+ E42962E62163EDD300A6A9E2 /* ofBaseTypes.h */,
+ E42962E42163EDD300A6A9E2 /* ofColor.cpp */,
+ E42962DC2163EDD300A6A9E2 /* ofColor.h */,
+ E42962E52163EDD300A6A9E2 /* ofParameter.cpp */,
+ E42962E32163EDD300A6A9E2 /* ofParameter.h */,
+ E42962E22163EDD300A6A9E2 /* ofParameterGroup.cpp */,
+ E42962DB2163EDD300A6A9E2 /* ofParameterGroup.h */,
+ E42962DE2163EDD300A6A9E2 /* ofPoint.h */,
+ E42962DD2163EDD300A6A9E2 /* ofRectangle.cpp */,
+ E42962E02163EDD300A6A9E2 /* ofRectangle.h */,
+ E42962DF2163EDD300A6A9E2 /* ofTypes.h */,
+ );
+ name = types;
+ path = ../../../libs/openFrameworks/types;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42962E72163EDD300A6A9E2 /* app */ = {
+ isa = PBXGroup;
+ children = (
+ E42962ED2163EDD300A6A9E2 /* ofAppBaseWindow.h */,
+ E42962EC2163EDD300A6A9E2 /* ofAppEGLWindow.cpp */,
+ E42962F12163EDD300A6A9E2 /* ofAppEGLWindow.h */,
+ E42962F52163EDD300A6A9E2 /* ofAppGLFWWindow.cpp */,
+ E42962F82163EDD300A6A9E2 /* ofAppGLFWWindow.h */,
+ E42962EA2163EDD300A6A9E2 /* ofAppGlutWindow.cpp */,
+ E42962F62163EDD300A6A9E2 /* ofAppGlutWindow.h */,
+ E42962F42163EDD300A6A9E2 /* ofAppNoWindow.cpp */,
+ E42962EF2163EDD300A6A9E2 /* ofAppNoWindow.h */,
+ E42962F72163EDD300A6A9E2 /* ofAppRunner.cpp */,
+ E42962F32163EDD300A6A9E2 /* ofAppRunner.h */,
+ E42962E92163EDD300A6A9E2 /* ofBaseApp.cpp */,
+ E42962F02163EDD300A6A9E2 /* ofBaseApp.h */,
+ E42962EE2163EDD300A6A9E2 /* ofIcon.h */,
+ E42962F22163EDD300A6A9E2 /* ofMainLoop.cpp */,
+ E42962E82163EDD300A6A9E2 /* ofMainLoop.h */,
+ E42962EB2163EDD300A6A9E2 /* ofWindowSettings.h */,
+ );
+ name = app;
+ path = ../../../libs/openFrameworks/app;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42962FA2163EDD300A6A9E2 /* utils */ = {
+ isa = PBXGroup;
+ children = (
+ E42962FF2163EDD300A6A9E2 /* ofConstants.h */,
+ E429630D2163EDD300A6A9E2 /* ofFileUtils.cpp */,
+ E42963092163EDD300A6A9E2 /* ofFileUtils.h */,
+ E42962FD2163EDD300A6A9E2 /* ofFpsCounter.cpp */,
+ E42963012163EDD300A6A9E2 /* ofFpsCounter.h */,
+ E429630C2163EDD300A6A9E2 /* ofJson.h */,
+ E42963072163EDD300A6A9E2 /* ofLog.cpp */,
+ E42963022163EDD300A6A9E2 /* ofLog.h */,
+ E429630E2163EDD300A6A9E2 /* ofMatrixStack.cpp */,
+ E42963112163EDD300A6A9E2 /* ofMatrixStack.h */,
+ E42963062163EDD300A6A9E2 /* ofNoise.h */,
+ E42963042163EDD300A6A9E2 /* ofSystemUtils.cpp */,
+ E42963032163EDD300A6A9E2 /* ofSystemUtils.h */,
+ E42962FC2163EDD300A6A9E2 /* ofThread.cpp */,
+ E429630A2163EDD300A6A9E2 /* ofThread.h */,
+ E42962FB2163EDD300A6A9E2 /* ofThreadChannel.h */,
+ E42963082163EDD300A6A9E2 /* ofTimer.cpp */,
+ E42963122163EDD300A6A9E2 /* ofTimer.h */,
+ E42962FE2163EDD300A6A9E2 /* ofURLFileLoader.cpp */,
+ E429630B2163EDD300A6A9E2 /* ofURLFileLoader.h */,
+ E429630F2163EDD300A6A9E2 /* ofUtils.cpp */,
+ E42963052163EDD300A6A9E2 /* ofUtils.h */,
+ E42963102163EDD300A6A9E2 /* ofXml.cpp */,
+ E42963002163EDD300A6A9E2 /* ofXml.h */,
+ );
+ name = utils;
+ path = ../../../libs/openFrameworks/utils;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42963132163EDD300A6A9E2 /* math */ = {
+ isa = PBXGroup;
+ children = (
+ E42963172163EDD300A6A9E2 /* ofMath.cpp */,
+ E429631C2163EDD300A6A9E2 /* ofMath.h */,
+ E42963182163EDD300A6A9E2 /* ofMathConstants.h */,
+ E429631B2163EDD300A6A9E2 /* ofMatrix3x3.cpp */,
+ E42963222163EDD300A6A9E2 /* ofMatrix3x3.h */,
+ E42963212163EDD300A6A9E2 /* ofMatrix4x4.cpp */,
+ E42963192163EDD300A6A9E2 /* ofMatrix4x4.h */,
+ E429631F2163EDD300A6A9E2 /* ofQuaternion.cpp */,
+ E429631D2163EDD300A6A9E2 /* ofQuaternion.h */,
+ E42963142163EDD300A6A9E2 /* ofVec2f.cpp */,
+ E42963202163EDD300A6A9E2 /* ofVec2f.h */,
+ E429631A2163EDD300A6A9E2 /* ofVec3f.h */,
+ E42963152163EDD300A6A9E2 /* ofVec4f.cpp */,
+ E42963162163EDD300A6A9E2 /* ofVec4f.h */,
+ E429631E2163EDD300A6A9E2 /* ofVectorMath.h */,
+ );
+ name = math;
+ path = ../../../libs/openFrameworks/math;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42963252163EDD300A6A9E2 /* gl */ = {
+ isa = PBXGroup;
+ children = (
+ E429632E2163EDD300A6A9E2 /* ofBufferObject.cpp */,
+ E42963332163EDD300A6A9E2 /* ofBufferObject.h */,
+ E429632A2163EDD300A6A9E2 /* ofFbo.cpp */,
+ E42963382163EDD300A6A9E2 /* ofFbo.h */,
+ E42963392163EDD300A6A9E2 /* ofGLBaseTypes.h */,
+ E42963342163EDD300A6A9E2 /* ofGLProgrammableRenderer.cpp */,
+ E429633B2163EDD300A6A9E2 /* ofGLProgrammableRenderer.h */,
+ E429633E2163EDD300A6A9E2 /* ofGLRenderer.cpp */,
+ E429633F2163EDD300A6A9E2 /* ofGLRenderer.h */,
+ E42963302163EDD300A6A9E2 /* ofGLUtils.cpp */,
+ E429633D2163EDD300A6A9E2 /* ofGLUtils.h */,
+ E42963322163EDD300A6A9E2 /* ofLight.cpp */,
+ E429632B2163EDD300A6A9E2 /* ofLight.h */,
+ E42963292163EDD300A6A9E2 /* ofMaterial.cpp */,
+ E429632C2163EDD300A6A9E2 /* ofMaterial.h */,
+ E429632D2163EDD300A6A9E2 /* ofShader.cpp */,
+ E42963282163EDD300A6A9E2 /* ofShader.h */,
+ E429633C2163EDD300A6A9E2 /* ofTexture.cpp */,
+ E42963272163EDD300A6A9E2 /* ofTexture.h */,
+ E429633A2163EDD300A6A9E2 /* ofVbo.cpp */,
+ E42963312163EDD300A6A9E2 /* ofVbo.h */,
+ E429632F2163EDD300A6A9E2 /* ofVboMesh.cpp */,
+ E42963262163EDD300A6A9E2 /* ofVboMesh.h */,
+ );
+ name = gl;
+ path = ../../../libs/openFrameworks/gl;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42963402163EDD300A6A9E2 /* communication */ = {
+ isa = PBXGroup;
+ children = (
+ E42963442163EDD300A6A9E2 /* ofArduino.cpp */,
+ E42963412163EDD300A6A9E2 /* ofArduino.h */,
+ E42963422163EDD300A6A9E2 /* ofSerial.cpp */,
+ E42963432163EDD300A6A9E2 /* ofSerial.h */,
+ );
+ name = communication;
+ path = ../../../libs/openFrameworks/communication;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42963452163EDD300A6A9E2 /* events */ = {
+ isa = PBXGroup;
+ children = (
+ E42963472163EDD300A6A9E2 /* ofEvent.h */,
+ E42963492163EDD300A6A9E2 /* ofEvents.cpp */,
+ E42963482163EDD300A6A9E2 /* ofEvents.h */,
+ E42963462163EDD300A6A9E2 /* ofEventUtils.h */,
+ );
+ name = events;
+ path = ../../../libs/openFrameworks/events;
+ sourceTree = SOURCE_ROOT;
+ };
+ E429634A2163EDD300A6A9E2 /* graphics */ = {
+ isa = PBXGroup;
+ children = (
+ E42963582163EDD300A6A9E2 /* of3dGraphics.cpp */,
+ E42963622163EDD300A6A9E2 /* of3dGraphics.h */,
+ E429634D2163EDD300A6A9E2 /* ofBitmapFont.cpp */,
+ E429635C2163EDD300A6A9E2 /* ofBitmapFont.h */,
+ E42963532163EDD300A6A9E2 /* ofCairoRenderer.cpp */,
+ E429635B2163EDD300A6A9E2 /* ofCairoRenderer.h */,
+ E42963502163EDD300A6A9E2 /* ofGraphics.cpp */,
+ E429635F2163EDD300A6A9E2 /* ofGraphics.h */,
+ E42963522163EDD300A6A9E2 /* ofGraphicsBaseTypes.cpp */,
+ E429634B2163EDD300A6A9E2 /* ofGraphicsBaseTypes.h */,
+ E42963602163EDD300A6A9E2 /* ofGraphicsConstants.h */,
+ E42963612163EDD300A6A9E2 /* ofImage.cpp */,
+ E42963592163EDD300A6A9E2 /* ofImage.h */,
+ E42963552163EDD300A6A9E2 /* ofPath.cpp */,
+ E429634C2163EDD300A6A9E2 /* ofPath.h */,
+ E42963562163EDD300A6A9E2 /* ofPixels.cpp */,
+ E429635A2163EDD300A6A9E2 /* ofPixels.h */,
+ E42963512163EDD300A6A9E2 /* ofPolyline.h */,
+ E42963572163EDD300A6A9E2 /* ofPolyline.inl */,
+ E42963542163EDD300A6A9E2 /* ofRendererCollection.cpp */,
+ E429635E2163EDD300A6A9E2 /* ofRendererCollection.h */,
+ E429634F2163EDD300A6A9E2 /* ofTessellator.cpp */,
+ E42963632163EDD300A6A9E2 /* ofTessellator.h */,
+ E429635D2163EDD300A6A9E2 /* ofTrueTypeFont.cpp */,
+ E429634E2163EDD300A6A9E2 /* ofTrueTypeFont.h */,
+ );
+ name = graphics;
+ path = ../../../libs/openFrameworks/graphics;
+ sourceTree = SOURCE_ROOT;
+ };
+ E42963642163EDD300A6A9E2 /* sound */ = {
+ isa = PBXGroup;
+ children = (
+ E429636A2163EDD300A6A9E2 /* ofFmodSoundPlayer.cpp */,
+ E42963712163EDD300A6A9E2 /* ofFmodSoundPlayer.h */,
+ E429636C2163EDD300A6A9E2 /* ofOpenALSoundPlayer.cpp */,
+ E42963682163EDD300A6A9E2 /* ofOpenALSoundPlayer.h */,
+ E42963692163EDD300A6A9E2 /* ofRtAudioSoundStream.cpp */,
+ E429636E2163EDD300A6A9E2 /* ofRtAudioSoundStream.h */,
+ E429636B2163EDD300A6A9E2 /* ofSoundBaseTypes.cpp */,
+ E42963732163EDD300A6A9E2 /* ofSoundBaseTypes.h */,
+ E42963722163EDD300A6A9E2 /* ofSoundBuffer.cpp */,
+ E42963702163EDD300A6A9E2 /* ofSoundBuffer.h */,
+ E429636D2163EDD300A6A9E2 /* ofSoundPlayer.cpp */,
+ E42963672163EDD300A6A9E2 /* ofSoundPlayer.h */,
+ E42963652163EDD300A6A9E2 /* ofSoundStream.cpp */,
+ E42963662163EDD300A6A9E2 /* ofSoundStream.h */,
+ E429636F2163EDD300A6A9E2 /* ofSoundUtils.h */,
+ );
+ name = sound;
+ path = ../../../libs/openFrameworks/sound;
+ sourceTree = SOURCE_ROOT;
+ };
+ E4B69B4A0A3A1720003C02F2 = {
+ isa = PBXGroup;
+ children = (
+ 8EF01BA62F7876DD00BF0971 /* example_slides */,
+ 8EF01BA42F7876C700BF0971 /* emotibitSlidePlayerSettings.json */,
+ E4B6FCAD0C3E899E008CF71C /* openFrameworks-Info.plist */,
+ E4EB6923138AFD0F00A09F29 /* Project.xcconfig */,
+ E4B69E1C0A3A1BDC003C02F2 /* src */,
+ E42962AA2163EDD300A6A9E2 /* openFrameworks */,
+ BB4B014C10F69532006C3DED /* addons */,
+ 6948EE371B920CB800B5AC1A /* local_addons */,
+ E4B69B5B0A3A1756003C02F2 /* SlidePlayerDebug.app */,
+ );
+ sourceTree = "";
+ };
+ E4B69E1C0A3A1BDC003C02F2 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ E4B69E1D0A3A1BDC003C02F2 /* main.cpp */,
+ E4B69E1E0A3A1BDC003C02F2 /* ofApp.cpp */,
+ E4B69E1F0A3A1BDC003C02F2 /* ofApp.h */,
+ );
+ path = src;
+ sourceTree = SOURCE_ROOT;
+ };
+ F40E80CB2D443CBA9581DD03 /* libs */ = {
+ isa = PBXGroup;
+ children = (
+ 977A836DD2C489CCC5E330FF /* jsoncpp */,
+ );
+ name = libs;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ E4B69B5A0A3A1756003C02F2 /* SlidePlayer */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = E4B69B5F0A3A1757003C02F2 /* Build configuration list for PBXNativeTarget "SlidePlayer" */;
+ buildPhases = (
+ E42962A92163ECCD00A6A9E2 /* ShellScript */,
+ E4B69B580A3A1756003C02F2 /* Sources */,
+ E4B69B590A3A1756003C02F2 /* Frameworks */,
+ E4B6FFFD0C3F9AB9008CF71C /* ShellScript */,
+ E4C2427710CC5ABF004149E2 /* CopyFiles */,
+ 8466F1851C04CA0E00918B1C /* ShellScript */,
+ 8EF01BA32F78768F00BF0971 /* Copy Settings and Example Slides */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SlidePlayer;
+ productName = myOFApp;
+ productReference = E4B69B5B0A3A1756003C02F2 /* SlidePlayerDebug.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ E4B69B4C0A3A1720003C02F2 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0600;
+ };
+ buildConfigurationList = E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "SlidePlayer" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = E4B69B4A0A3A1720003C02F2;
+ productRefGroup = E4B69B4A0A3A1720003C02F2;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ E4B69B5A0A3A1756003C02F2 /* SlidePlayer */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 8466F1851C04CA0E00918B1C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 12;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "echo \"$GCC_PREPROCESSOR_DEFINITIONS\";\nAPPSTORE=`expr \"$GCC_PREPROCESSOR_DEFINITIONS\" : \".*APPSTORE=\\([0-9]*\\)\"`\nif [ -z \"$APPSTORE\" ] ; then\necho \"Note: Not copying bin/data to App Package or doing App Code signing. Use AppStore target for AppStore distribution\";\nelse\n# Copy bin/data into App/Resources\nrsync -avz --exclude='.DS_Store' \"${SRCROOT}/bin/data/\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/data/\"\n\n# ---- Code Sign App Package ----\n\n# WARNING: You may have to run Clean in Xcode after changing CODE_SIGN_IDENTITY!\n\n# Verify that $CODE_SIGN_IDENTITY is set\nif [ -z \"${CODE_SIGN_IDENTITY}\" ] ; then\necho \"CODE_SIGN_IDENTITY needs to be set for framework code-signing\"\nexit 0\nfi\n\nif [ -z \"${CODE_SIGN_ENTITLEMENTS}\" ] ; then\necho \"CODE_SIGN_ENTITLEMENTS needs to be set for framework code-signing!\"\n\nif [ \"${CONFIGURATION}\" = \"Release\" ] ; then\nexit 1\nelse\n# Code-signing is optional for non-release builds.\nexit 0\nfi\nfi\n\nITEMS=\"\"\n\nFRAMEWORKS_DIR=\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}\"\necho \"$FRAMEWORKS_DIR\"\nif [ -d \"$FRAMEWORKS_DIR\" ] ; then\nFRAMEWORKS=$(find \"${FRAMEWORKS_DIR}\" -depth -type d -name \"*.framework\" -or -name \"*.dylib\" -or -name \"*.bundle\" | sed -e \"s/\\(.*framework\\)/\\1\\/Versions\\/A\\//\")\nRESULT=$?\nif [[ $RESULT != 0 ]] ; then\nexit 1\nfi\n\nITEMS=\"${FRAMEWORKS}\"\nfi\n\nLOGINITEMS_DIR=\"${TARGET_BUILD_DIR}/${CONTENTS_FOLDER_PATH}/Library/LoginItems/\"\nif [ -d \"$LOGINITEMS_DIR\" ] ; then\nLOGINITEMS=$(find \"${LOGINITEMS_DIR}\" -depth -type d -name \"*.app\")\nRESULT=$?\nif [[ $RESULT != 0 ]] ; then\nexit 1\nfi\n\nITEMS=\"${ITEMS}\"$'\\n'\"${LOGINITEMS}\"\nfi\n\n# Prefer the expanded name, if available.\nCODE_SIGN_IDENTITY_FOR_ITEMS=\"${EXPANDED_CODE_SIGN_IDENTITY_NAME}\"\nif [ \"${CODE_SIGN_IDENTITY_FOR_ITEMS}\" = \"\" ] ; then\n# Fall back to old behavior.\nCODE_SIGN_IDENTITY_FOR_ITEMS=\"${CODE_SIGN_IDENTITY}\"\nfi\n\necho \"Identity:\"\necho \"${CODE_SIGN_IDENTITY_FOR_ITEMS}\"\n\necho \"Entitlements:\"\necho \"${CODE_SIGN_ENTITLEMENTS}\"\n\necho \"Found:\"\necho \"${ITEMS}\"\n\n# Change the Internal Field Separator (IFS) so that spaces in paths will not cause problems below.\nSAVED_IFS=$IFS\nIFS=$(echo -en \"\\n\\b\")\n\n# Loop through all items.\nfor ITEM in $ITEMS;\ndo\necho \"Stripping invalid archs '${ITEM}'\"\nlipo -extract x86_64 \"${ITEM}\" -o \"${ITEM}\"\necho \"Signing '${ITEM}'\"\ncodesign --force --verbose --sign \"${CODE_SIGN_IDENTITY_FOR_ITEMS}\" --entitlements \"${CODE_SIGN_ENTITLEMENTS}\" \"${ITEM}\"\nRESULT=$?\nif [[ $RESULT != 0 ]] ; then\necho \"Failed to sign '${ITEM}'.\"\nIFS=$SAVED_IFS\nexit 1\nfi\ndone\n\n# Restore $IFS.\nIFS=$SAVED_IFS\n\nfi\n";
+ };
+ E42962A92163ECCD00A6A9E2 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "xcodebuild -project \"$OF_PATH/libs/openFrameworksCompiled/project/osx/openFrameworksLib.xcodeproj\" -target openFrameworks -configuration \"${CONFIGURATION}\"";
+ };
+ E4B6FFFD0C3F9AB9008CF71C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "mkdir -p \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/\"\n# Copy default icon file into App/Resources\nrsync -aved \"$ICON_FILE\" \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Resources/\"\n# Copy libfmod and change install directory for fmod to run\nrsync -aved \"$OF_PATH/libs/fmod/lib/osx/libfmod.dylib\" \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/Frameworks/\";\n# Not needed as we now call install_name_tool -id @loader_path/../Frameworks/libfmod.dylib libfmod.dylib on the dylib directly which prevents the need for calling every post build - keeping here for reference and possible legacy usage \n# install_name_tool -change @rpath/libfmod.dylib @executable_path/../Frameworks/libfmod.dylib \"$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME\";\n\necho \"$GCC_PREPROCESSOR_DEFINITIONS\";\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ E4B69B580A3A1756003C02F2 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */,
+ E4B69E210A3A1BDC003C02F2 /* ofApp.cpp in Sources */,
+ FB84AAF8D1B7A95266DB5C09 /* jsoncpp.cpp in Sources */,
+ BEDFEE7400C58EA4E412B757 /* ofxJSONElement.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 99FA3DBB1C7456C400CFA0EE /* AppStore */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "$(SRCROOT)/bin/";
+ COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
+ GCC_AUTO_VECTORIZATION = YES;
+ GCC_ENABLE_SSE3_EXTENSIONS = YES;
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "DISTRIBUTION=1";
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_UNROLL_LOOPS = YES;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNUSED_VALUE = NO;
+ GCC_WARN_UNUSED_VARIABLE = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(OF_CORE_HEADERS)",
+ src,
+ ../../../addons/ofxJSON/libs,
+ ../../../addons/ofxJSON/libs/jsoncpp,
+ ../../../addons/ofxJSON/libs/jsoncpp/include,
+ ../../../addons/ofxJSON/libs/jsoncpp/include/json,
+ ../../../addons/ofxJSON/libs/jsoncpp/src,
+ ../../../addons/ofxJSON/src,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ OTHER_CODE_SIGN_FLAGS = "--deep";
+ OTHER_CPLUSPLUSFLAGS = "-D__MACOSX_CORE__";
+ SDKROOT = macosx;
+ };
+ name = AppStore;
+ };
+ 99FA3DBC1C7456C400CFA0EE /* AppStore */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = YES;
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = NONE;
+ "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "APPSTORE=1";
+ HEADER_SEARCH_PATHS = (
+ "$(OF_CORE_HEADERS)",
+ src,
+ ../../../addons/ofxJSON/libs,
+ ../../../addons/ofxJSON/libs/jsoncpp,
+ ../../../addons/ofxJSON/libs/jsoncpp/include,
+ ../../../addons/ofxJSON/libs/jsoncpp/include/json,
+ ../../../addons/ofxJSON/libs/jsoncpp/src,
+ ../../../addons/ofxJSON/src,
+ );
+ ICON = EmotiBit.icns;
+ ICON_FILE = ../EmotiBitIcons/macOS/EmotiBit.icns;
+ ICON_FILE_PATH = ../EmotiBitIcons/macOS;
+ ICON_NAME_DEBUG = EmotiBit.icns;
+ ICON_NAME_RELEASE = EmotiBit.icns;
+ INFOPLIST_FILE = "openFrameworks-Info.plist";
+ INSTALL_PATH = /Applications;
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(OF_CORE_LIBS)",
+ "$(OF_CORE_FRAMEWORKS)",
+ "$(LIB_OF)",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29;
+ };
+ name = AppStore;
+ };
+ E4B69B4E0A3A1720003C02F2 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "$(SRCROOT)/bin/";
+ COPY_PHASE_STRIP = NO;
+ DEAD_CODE_STRIPPING = YES;
+ GCC_AUTO_VECTORIZATION = YES;
+ GCC_ENABLE_SSE3_EXTENSIONS = YES;
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNUSED_VALUE = NO;
+ GCC_WARN_UNUSED_VARIABLE = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(OF_CORE_HEADERS)",
+ src,
+ ../../../addons/ofxJSON/libs,
+ ../../../addons/ofxJSON/libs/jsoncpp,
+ ../../../addons/ofxJSON/libs/jsoncpp/include,
+ ../../../addons/ofxJSON/libs/jsoncpp/include/json,
+ ../../../addons/ofxJSON/libs/jsoncpp/src,
+ ../../../addons/ofxJSON/src,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ ONLY_ACTIVE_ARCH = YES;
+ OTHER_CODE_SIGN_FLAGS = "--deep";
+ OTHER_CPLUSPLUSFLAGS = "-D__MACOSX_CORE__";
+ SDKROOT = macosx;
+ };
+ name = Debug;
+ };
+ E4B69B4F0A3A1720003C02F2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */;
+ buildSettings = {
+ CONFIGURATION_BUILD_DIR = "$(SRCROOT)/bin/";
+ COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
+ GCC_AUTO_VECTORIZATION = YES;
+ GCC_ENABLE_SSE3_EXTENSIONS = YES;
+ GCC_ENABLE_SUPPLEMENTAL_SSE3_INSTRUCTIONS = YES;
+ GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
+ GCC_OPTIMIZATION_LEVEL = 3;
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_UNROLL_LOOPS = YES;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
+ GCC_WARN_ABOUT_INVALID_OFFSETOF_MACRO = NO;
+ GCC_WARN_ALLOW_INCOMPLETE_PROTOCOL = NO;
+ GCC_WARN_UNINITIALIZED_AUTOS = NO;
+ GCC_WARN_UNUSED_VALUE = NO;
+ GCC_WARN_UNUSED_VARIABLE = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(OF_CORE_HEADERS)",
+ src,
+ ../../../addons/ofxJSON/libs,
+ ../../../addons/ofxJSON/libs/jsoncpp,
+ ../../../addons/ofxJSON/libs/jsoncpp/include,
+ ../../../addons/ofxJSON/libs/jsoncpp/include/json,
+ ../../../addons/ofxJSON/libs/jsoncpp/src,
+ ../../../addons/ofxJSON/src,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.9;
+ OTHER_CODE_SIGN_FLAGS = "--deep";
+ OTHER_CPLUSPLUSFLAGS = "-D__MACOSX_CORE__";
+ SDKROOT = macosx;
+ };
+ name = Release;
+ };
+ E4B69B600A3A1757003C02F2 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = NO;
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = NONE;
+ HEADER_SEARCH_PATHS = (
+ "$(OF_CORE_HEADERS)",
+ src,
+ ../../../addons/ofxJSON/libs,
+ ../../../addons/ofxJSON/libs/jsoncpp,
+ ../../../addons/ofxJSON/libs/jsoncpp/include,
+ ../../../addons/ofxJSON/libs/jsoncpp/include/json,
+ ../../../addons/ofxJSON/libs/jsoncpp/src,
+ ../../../addons/ofxJSON/src,
+ );
+ ICON = EmotiBit.icns;
+ ICON_FILE = ../EmotiBitIcons/macOS/EmotiBit.icns;
+ ICON_FILE_PATH = ../EmotiBitIcons/macOS;
+ ICON_NAME_DEBUG = EmotiBit.icns;
+ ICON_NAME_RELEASE = EmotiBit.icns;
+ INFOPLIST_FILE = "openFrameworks-Info.plist";
+ INSTALL_PATH = /Applications;
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(OF_CORE_LIBS)",
+ "$(OF_CORE_FRAMEWORKS)",
+ "$(LIB_OF_DEBUG)",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)Debug";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ E4B69B610A3A1757003C02F2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29 /* Project.xcconfig */;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = YES;
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+ GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+ GCC_MODEL_TUNING = NONE;
+ HEADER_SEARCH_PATHS = (
+ "$(OF_CORE_HEADERS)",
+ src,
+ ../../../addons/ofxJSON/libs,
+ ../../../addons/ofxJSON/libs/jsoncpp,
+ ../../../addons/ofxJSON/libs/jsoncpp/include,
+ ../../../addons/ofxJSON/libs/jsoncpp/include/json,
+ ../../../addons/ofxJSON/libs/jsoncpp/src,
+ ../../../addons/ofxJSON/src,
+ );
+ ICON = EmotiBit.icns;
+ ICON_FILE = ../EmotiBitIcons/macOS/EmotiBit.icns;
+ ICON_FILE_PATH = ../EmotiBitIcons/macOS;
+ ICON_NAME_DEBUG = EmotiBit.icns;
+ ICON_NAME_RELEASE = EmotiBit.icns;
+ INFOPLIST_FILE = "openFrameworks-Info.plist";
+ INSTALL_PATH = /Applications;
+ LIBRARY_SEARCH_PATHS = "$(inherited)";
+ OTHER_LDFLAGS = (
+ "$(OF_CORE_LIBS)",
+ "$(OF_CORE_FRAMEWORKS)",
+ "$(LIB_OF)",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ WRAPPER_EXTENSION = app;
+ baseConfigurationReference = E4EB6923138AFD0F00A09F29;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ E4B69B4D0A3A1720003C02F2 /* Build configuration list for PBXProject "SlidePlayer" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ E4B69B4E0A3A1720003C02F2 /* Debug */,
+ E4B69B4F0A3A1720003C02F2 /* Release */,
+ 99FA3DBB1C7456C400CFA0EE /* AppStore */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ E4B69B5F0A3A1757003C02F2 /* Build configuration list for PBXNativeTarget "SlidePlayer" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ E4B69B600A3A1757003C02F2 /* Debug */,
+ E4B69B610A3A1757003C02F2 /* Release */,
+ 99FA3DBC1C7456C400CFA0EE /* AppStore */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = E4B69B4C0A3A1720003C02F2 /* Project object */;
+}
diff --git a/SlidePlayer/SlidePlayer.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme b/SlidePlayer/SlidePlayer.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme
new file mode 100644
index 0000000..c8b2824
--- /dev/null
+++ b/SlidePlayer/SlidePlayer.xcodeproj/xcshareddata/xcschemes/Debug.xcscheme
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SlidePlayer/SlidePlayer.xcodeproj/xcshareddata/xcschemes/Release.xcscheme b/SlidePlayer/SlidePlayer.xcodeproj/xcshareddata/xcschemes/Release.xcscheme
new file mode 100644
index 0000000..d05b120
--- /dev/null
+++ b/SlidePlayer/SlidePlayer.xcodeproj/xcshareddata/xcschemes/Release.xcscheme
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SlidePlayer/addons.make b/SlidePlayer/addons.make
new file mode 100644
index 0000000..ab5217b
--- /dev/null
+++ b/SlidePlayer/addons.make
@@ -0,0 +1 @@
+ofxJSON
diff --git a/SlidePlayer/bin/data/emotibitSlidePlayerSettings.json b/SlidePlayer/bin/data/emotibitSlidePlayerSettings.json
new file mode 100644
index 0000000..b7450b3
--- /dev/null
+++ b/SlidePlayer/bin/data/emotibitSlidePlayerSettings.json
@@ -0,0 +1,44 @@
+{
+ "globalSlideSettings": {
+ "background": "example_slides/default_slides/default_background.png",
+ "slideSetIntroSlide": "example_slides/default_slides/default_intro_slide.png",
+ "pauseOnSetIntroSlide": true,
+ "slideSetIntroSlideTimeMin_msec": 4000, // durations are randomized in between min and max
+ "slideSetIntroSlideTimeMax_msec": 10000,
+ "slideOrderRandomization": true,
+ "maxSlidesPerSet": 5, // number of slides to play from each set
+ "slideOnTimeMin_msec": 3000,
+ "slideOnTimeMax_msec": 3000,
+ "slideOffTimeMin_msec": 1000,
+ "slideOffTimeMax_msec": 2000
+ },
+ "appSettings": {
+ "keyboardControls": {
+ "toggleFullScreen": "F",
+ "nextSlide": "N",
+ "previousSlide": "B",
+ "pauseSlideshowToggle": "P",
+ "restartSlideshow": "R",
+ "restartSlideSet": "T",
+ "loadSettingsFile": "S",
+ "setLogFileDirectory": "L"
+ },
+ "logFileDirectory": "",
+ "startFullScreen": true,
+ "startPaused": true
+ },
+ "slideSets": [
+ // At the beginning of each slideSet the globalSlideSettings are reloaded
+ // and then the slideSet-specific settings are loaded
+ {
+ "slideDirectory": "example_slides/set-1",
+ "slideOrderRandomization": false,
+ "slideSetIntroSlide": "example_slides/set-1/set_1-Intro_slide.png"
+ },
+ {
+ "slideDirectory": "example_slides/set-2",
+ "slideOrderRandomization": false,
+ "background": "example_slides/set-2/set_2-background.png"
+ }
+ ]
+}
diff --git a/SlidePlayer/bin/data/example_slides/default_slides/default_background.png b/SlidePlayer/bin/data/example_slides/default_slides/default_background.png
new file mode 100644
index 0000000..0cabc43
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/default_slides/default_background.png differ
diff --git a/SlidePlayer/bin/data/example_slides/default_slides/default_intro_slide.png b/SlidePlayer/bin/data/example_slides/default_slides/default_intro_slide.png
new file mode 100644
index 0000000..43d422f
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/default_slides/default_intro_slide.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-1/set_1-Intro_slide.png b/SlidePlayer/bin/data/example_slides/set-1/set_1-Intro_slide.png
new file mode 100644
index 0000000..491f675
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-1/set_1-Intro_slide.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_1.png b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_1.png
new file mode 100644
index 0000000..542f274
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_1.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_2.png b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_2.png
new file mode 100644
index 0000000..1719a80
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_2.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_3.png b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_3.png
new file mode 100644
index 0000000..6224c16
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_3.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_4.png b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_4.png
new file mode 100644
index 0000000..5c42689
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-1/set_1-slide_4.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-2/set_2-background.png b/SlidePlayer/bin/data/example_slides/set-2/set_2-background.png
new file mode 100644
index 0000000..9bb0946
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-2/set_2-background.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_1.png b/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_1.png
new file mode 100644
index 0000000..ef55c28
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_1.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_2.png b/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_2.png
new file mode 100644
index 0000000..909d8c1
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_2.png differ
diff --git a/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_3.png b/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_3.png
new file mode 100644
index 0000000..4402d07
Binary files /dev/null and b/SlidePlayer/bin/data/example_slides/set-2/set_2-slide_3.png differ
diff --git a/SlidePlayer/compile_flags.txt b/SlidePlayer/compile_flags.txt
new file mode 100644
index 0000000..241bdc9
--- /dev/null
+++ b/SlidePlayer/compile_flags.txt
@@ -0,0 +1,37 @@
+-std=c++23
+-xc++
+-DMACOSX
+-DGL_SILENCE_DEPRECATION=1
+-DGLES_SILENCE_DEPRECATION=1
+-DCOREVIDEO_SILENCE_GL_DEPRECATION=1
+-DGLM_FORCE_CTOR_INIT
+-DGLM_ENABLE_EXPERIMENTAL
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/3d
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/app
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/communication
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/events
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/gl
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/graphics
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/math
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/sound
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/types
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/utils
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openFrameworks/video
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/freetype/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/freetype/include/freetype2
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/glew/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/FreeImage/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/tess2/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/cairo/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/rtAudio/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/glfw/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/utf8/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/json/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/glm/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/curl/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/openssl/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/uriparser/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/pugixml/include
+-I/Users/nnair/CFL/dev/EmotiBit/Software/of_v0.12.1_osx_release/libs/brotli/include
+-Isrc
diff --git a/SlidePlayer/config.make b/SlidePlayer/config.make
new file mode 100644
index 0000000..5a719bc
--- /dev/null
+++ b/SlidePlayer/config.make
@@ -0,0 +1,142 @@
+################################################################################
+# CONFIGURE PROJECT MAKEFILE (optional)
+# This file is where we make project specific configurations.
+################################################################################
+
+################################################################################
+# OF ROOT
+# The location of your root openFrameworks installation
+# (default) OF_ROOT = ../../..
+################################################################################
+OF_ROOT = /Users/cfl/dev/emotibit/software/local_dev/of_v0.11.2_osx_release
+
+################################################################################
+# PROJECT ROOT
+# The location of the project - a starting place for searching for files
+# (default) PROJECT_ROOT = . (this directory)
+#
+################################################################################
+# PROJECT_ROOT = .
+
+################################################################################
+# PROJECT SPECIFIC CHECKS
+# This is a project defined section to create internal makefile flags to
+# conditionally enable or disable the addition of various features within
+# this makefile. For instance, if you want to make changes based on whether
+# GTK is installed, one might test that here and create a variable to check.
+################################################################################
+# None
+
+################################################################################
+# PROJECT EXTERNAL SOURCE PATHS
+# These are fully qualified paths that are not within the PROJECT_ROOT folder.
+# Like source folders in the PROJECT_ROOT, these paths are subject to
+# exlclusion via the PROJECT_EXLCUSIONS list.
+#
+# (default) PROJECT_EXTERNAL_SOURCE_PATHS = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXTERNAL_SOURCE_PATHS =
+
+################################################################################
+# PROJECT EXCLUSIONS
+# These makefiles assume that all folders in your current project directory
+# and any listed in the PROJECT_EXTERNAL_SOURCH_PATHS are are valid locations
+# to look for source code. The any folders or files that match any of the
+# items in the PROJECT_EXCLUSIONS list below will be ignored.
+#
+# Each item in the PROJECT_EXCLUSIONS list will be treated as a complete
+# string unless teh user adds a wildcard (%) operator to match subdirectories.
+# GNU make only allows one wildcard for matching. The second wildcard (%) is
+# treated literally.
+#
+# (default) PROJECT_EXCLUSIONS = (blank)
+#
+# Will automatically exclude the following:
+#
+# $(PROJECT_ROOT)/bin%
+# $(PROJECT_ROOT)/obj%
+# $(PROJECT_ROOT)/%.xcodeproj
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_EXCLUSIONS =
+
+################################################################################
+# PROJECT LINKER FLAGS
+# These flags will be sent to the linker when compiling the executable.
+#
+# (default) PROJECT_LDFLAGS = -Wl,-rpath=./libs
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+
+# Currently, shared libraries that are needed are copied to the
+# $(PROJECT_ROOT)/bin/libs directory. The following LDFLAGS tell the linker to
+# add a runtime path to search for those shared libraries, since they aren't
+# incorporated directly into the final executable application binary.
+# TODO: should this be a default setting?
+# PROJECT_LDFLAGS=-Wl,-rpath=./libs
+
+################################################################################
+# PROJECT DEFINES
+# Create a space-delimited list of DEFINES. The list will be converted into
+# CFLAGS with the "-D" flag later in the makefile.
+#
+# (default) PROJECT_DEFINES = (blank)
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_DEFINES =
+
+################################################################################
+# PROJECT CFLAGS
+# This is a list of fully qualified CFLAGS required when compiling for this
+# project. These CFLAGS will be used IN ADDITION TO the PLATFORM_CFLAGS
+# defined in your platform specific core configuration files. These flags are
+# presented to the compiler BEFORE the PROJECT_OPTIMIZATION_CFLAGS below.
+#
+# (default) PROJECT_CFLAGS = (blank)
+#
+# Note: Before adding PROJECT_CFLAGS, note that the PLATFORM_CFLAGS defined in
+# your platform specific configuration file will be applied by default and
+# further flags here may not be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CFLAGS =
+
+################################################################################
+# PROJECT OPTIMIZATION CFLAGS
+# These are lists of CFLAGS that are target-specific. While any flags could
+# be conditionally added, they are usually limited to optimization flags.
+# These flags are added BEFORE the PROJECT_CFLAGS.
+#
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE flags are only applied to RELEASE targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_RELEASE = (blank)
+#
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG flags are only applied to DEBUG targets.
+#
+# (default) PROJECT_OPTIMIZATION_CFLAGS_DEBUG = (blank)
+#
+# Note: Before adding PROJECT_OPTIMIZATION_CFLAGS, please note that the
+# PLATFORM_OPTIMIZATION_CFLAGS defined in your platform specific configuration
+# file will be applied by default and further optimization flags here may not
+# be needed.
+#
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_OPTIMIZATION_CFLAGS_RELEASE =
+# PROJECT_OPTIMIZATION_CFLAGS_DEBUG =
+
+################################################################################
+# PROJECT COMPILERS
+# Custom compilers can be set for CC and CXX
+# (default) PROJECT_CXX = (blank)
+# (default) PROJECT_CC = (blank)
+# Note: Leave a leading space when adding list items with the += operator
+################################################################################
+# PROJECT_CXX =
+# PROJECT_CC =
diff --git a/SlidePlayer/icon.rc b/SlidePlayer/icon.rc
new file mode 100644
index 0000000..1ac16e0
--- /dev/null
+++ b/SlidePlayer/icon.rc
@@ -0,0 +1,9 @@
+// Icon Resource Definition
+#define MAIN_ICON 102
+
+MAIN_ICON ICON "..\EmotiBitIcons\icoFiles\EmotiBitLogo.ico"
+//#if defined(_DEBUG)
+//MAIN_ICON ICON "..\EmotiBitIcons\icoFiles\EmotiBitLogo.ico"
+//#else
+//MAIN_ICON ICON "..\EmotiBitIcons\icoFiles\EmotiBitLogo.ico"
+//#endif
diff --git a/SlidePlayer/openFrameworks-Info.plist b/SlidePlayer/openFrameworks-Info.plist
new file mode 100644
index 0000000..ba13aec
--- /dev/null
+++ b/SlidePlayer/openFrameworks-Info.plist
@@ -0,0 +1,28 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIdentifier
+ cc.openFrameworks.${EXECUTABLE_NAME}
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ CFBundleIconFile
+ ${ICON}
+ NSCameraUsageDescription
+ This app needs to access the camera
+ NSMicrophoneUsageDescription
+ This app needs to access the microphone
+ NSHighResolutionCapable
+
+
+
diff --git a/SlidePlayer/src/main.cpp b/SlidePlayer/src/main.cpp
new file mode 100644
index 0000000..9887d90
--- /dev/null
+++ b/SlidePlayer/src/main.cpp
@@ -0,0 +1,7 @@
+#include "ofApp.h"
+#include "ofMain.h"
+
+int main() {
+ ofSetupOpenGL(1024, 768, OF_WINDOW);
+ ofRunApp(new ofApp());
+}
diff --git a/SlidePlayer/src/ofApp.cpp b/SlidePlayer/src/ofApp.cpp
new file mode 100644
index 0000000..713b056
--- /dev/null
+++ b/SlidePlayer/src/ofApp.cpp
@@ -0,0 +1,691 @@
+#include "ofApp.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "json/json.h"
+#include "ofAppRunner.h"
+#include "ofFileUtils.h"
+#include "ofImage.h"
+#include "ofUtils.h"
+
+// ── Setup
+// ─────────────────────────────────────────────────────────────────────
+
+void ofApp::ensureSettingsFile()
+{
+ std::string docs_dir = ofFilePath::join(
+ ofFilePath::join(
+ ofFilePath::join(ofFilePath::getUserHomeDir(), "Documents"),
+ "EmotiBit"),
+ "SlidePlayer");
+ std::string target_path = ofFilePath::join(docs_dir, settings_file_name_);
+ if (!ofFile(target_path).exists())
+ {
+ ofDirectory::createDirectory(docs_dir, false, true);
+ ofFile source(ofToDataPath(settings_file_name_), ofFile::Reference,
+ false);
+ source.copyTo(target_path, false, false);
+ }
+ else
+ {
+ std::cout << "Settings file already exists at: " << target_path
+ << ". Use this file to specify app settings" << std::endl;
+ }
+ settings_file_name_ = target_path;
+}
+
+void ofApp::setup()
+{
+#ifdef TARGET_OSX
+ ofSetDataPathRoot("../Resources");
+#endif
+ ensureSettingsFile();
+ ofSetLogLevel(OF_LOG_SILENT);
+ if (!loadAppSettings())
+ {
+ std::cerr << "App settings file not found. Quitting" << std::endl;
+ ofExit();
+ }
+ startLogToFile();
+ logEvent("APP_START", "settings=" + settings_file_name_ +
+ " log_dir=" + app_settings_.log_file_directory_);
+ logEvent("SETTINGS_JSON", settings_json_);
+ for (int i = 0; i < (int)app_settings_.slide_sets_.size(); i++)
+ {
+ const auto& ss = app_settings_.slide_sets_[i];
+ logEvent("SETTINGS_LOAD",
+ "set_index=" + std::to_string(i) +
+ " dir=" + ss.slide_directory_ + " max_slides=" +
+ std::to_string(ss.settings_.max_slides_per_set_) +
+ " randomize=" +
+ std::to_string(ss.settings_.slide_order_randomization_));
+ }
+}
+
+bool ofApp::loadAppSettings()
+{
+ ofFile emotibit_slide_player_settings(settings_file_name_);
+ std::string json_str;
+ if (emotibit_slide_player_settings.exists())
+ {
+ ofBuffer buf = emotibit_slide_player_settings.readToBuffer();
+ json_str = buf.getText();
+ }
+ else
+ {
+ std::cerr << "Error: file not found - "
+ << emotibit_slide_player_settings.getAbsolutePath()
+ << std::endl;
+ return false;
+ }
+
+ Json::Reader reader;
+ Json::Value root;
+ if (!reader.parse(json_str, root))
+ {
+ std::cerr << "JSON parsing failed" << std::endl;
+ return false;
+ }
+ Json::FastWriter writer;
+ settings_json_ = writer.write(root);
+ // FastWriter appends a trailing newline — strip it for clean CSV embedding
+ if (!settings_json_.empty() && settings_json_.back() == '\n')
+ {
+ settings_json_.pop_back();
+ }
+ return parseSettings(root);
+}
+
+bool ofApp::parseSettings(const Json::Value& settings)
+{
+ if (settings.isMember("appSettings"))
+ {
+ const Json::Value& app = settings["appSettings"];
+
+ if (app.isMember("logFileDirectory") &&
+ !app["logFileDirectory"].asString().empty())
+ {
+ app_settings_.log_file_directory_ =
+ app["logFileDirectory"].asString();
+ }
+ else
+ {
+ app_settings_.log_file_directory_ = ofFilePath::join(
+ ofFilePath::join(
+ ofFilePath::join(
+ ofFilePath::join(ofFilePath::getUserHomeDir(),
+ "Documents"),
+ "EmotiBit"),
+ "SlidePlayer"),
+ "log");
+ std::cerr
+ << "Warning: log file directory not specified. Using default: "
+ << app_settings_.log_file_directory_ << std::endl;
+ }
+
+ if (app.isMember("startFullScreen") && app["startFullScreen"].isBool())
+ {
+ app_settings_.start_full_screen_ = app["startFullScreen"].asBool();
+ }
+ else
+ {
+ std::cerr << "Error: startFullScreen not specified in settings file"
+ << std::endl;
+ }
+
+ if (app.isMember("startPaused") && app["startPaused"].isBool())
+ {
+ app_settings_.start_paused_ = app["startPaused"].asBool();
+ }
+ else
+ {
+ std::cerr << "Error: startPaused not specified in settings file"
+ << std::endl;
+ }
+
+ if (app.isMember("keyboardControls"))
+ {
+ const Json::Value& kc = app["keyboardControls"];
+ auto load_key = [](const Json::Value& node, const std::string& key,
+ char& target)
+ {
+ if (node.isMember(key) && !node[key].asString().empty())
+ {
+ target = node[key].asString()[0];
+ }
+ };
+ load_key(kc, "toggleFullScreen",
+ app_settings_.keyboard_controls_.toggle_full_screen_);
+ load_key(kc, "nextSlide",
+ app_settings_.keyboard_controls_.next_slide_);
+ load_key(kc, "previousSlide",
+ app_settings_.keyboard_controls_.previous_slide_);
+ load_key(kc, "pauseSlideshowToggle",
+ app_settings_.keyboard_controls_.pause_slide_show_toggle_);
+ load_key(kc, "restartSlideshow",
+ app_settings_.keyboard_controls_.restart_slide_show_);
+ load_key(kc, "restartSlideSet",
+ app_settings_.keyboard_controls_.restart_slide_set_);
+ load_key(kc, "loadSettingsFile",
+ app_settings_.keyboard_controls_.load_settings_file_);
+ load_key(kc, "setLogFileDirectory",
+ app_settings_.keyboard_controls_.set_log_file_directory_);
+ }
+ else
+ {
+ std::cerr
+ << "Error: keyboardControls not specified in settings file"
+ << std::endl;
+ }
+ }
+ else
+ {
+ std::cerr << "Error: appSettings not specified" << std::endl;
+ }
+
+ auto resolve_path = [](const std::string& path) -> std::string
+ { return ofFilePath::isAbsolute(path) ? path : ofToDataPath(path, true); };
+
+ auto load_slide_settings =
+ [&resolve_path](const Json::Value& node, AppSettings::SlideSettings& s)
+ {
+ if (node.isMember("background"))
+ {
+ s.background_ = resolve_path(node["background"].asString());
+ }
+ if (node.isMember("slideSetIntroSlide"))
+ {
+ s.slide_set_intro_slide_ =
+ resolve_path(node["slideSetIntroSlide"].asString());
+ }
+ if (node.isMember("pauseOnSetIntroSlide"))
+ {
+ s.pause_on_set_intro_slide_ = node["pauseOnSetIntroSlide"].asBool();
+ }
+ if (node.isMember("slideSetIntroSlideTimeMin_msec"))
+ {
+ s.slide_set_intro_slide_time_min_msec_ =
+ node["slideSetIntroSlideTimeMin_msec"].asFloat();
+ }
+ if (node.isMember("slideSetIntroSlideTimeMax_msec"))
+ {
+ s.slide_set_intro_slide_time_max_msec_ =
+ node["slideSetIntroSlideTimeMax_msec"].asFloat();
+ }
+ if (node.isMember("slideOrderRandomization"))
+ {
+ s.slide_order_randomization_ =
+ node["slideOrderRandomization"].asBool();
+ }
+ if (node.isMember("maxSlidesPerSet"))
+ {
+ s.max_slides_per_set_ = node["maxSlidesPerSet"].asInt();
+ }
+ if (node.isMember("slideOnTimeMin_msec"))
+ {
+ s.slide_on_time_min_msec_ = node["slideOnTimeMin_msec"].asFloat();
+ }
+ if (node.isMember("slideOnTimeMax_msec"))
+ {
+ s.slide_on_time_max_msec_ = node["slideOnTimeMax_msec"].asFloat();
+ }
+ if (node.isMember("slideOffTimeMin_msec"))
+ {
+ s.slide_off_time_min_msec_ = node["slideOffTimeMin_msec"].asFloat();
+ }
+ if (node.isMember("slideOffTimeMax_msec"))
+ {
+ s.slide_off_time_max_msec_ = node["slideOffTimeMax_msec"].asFloat();
+ }
+ };
+
+ if (settings.isMember("globalSlideSettings"))
+ {
+ load_slide_settings(settings["globalSlideSettings"],
+ app_settings_.global_slide_settings_);
+ }
+ else
+ {
+ std::cerr << "Error: globalSlideSettings not specified" << std::endl;
+ }
+
+ if (settings.isMember("slideSets"))
+ {
+ uint16_t num_slide_sets = settings["slideSets"].size();
+ for (int i = 0; i < num_slide_sets; i++)
+ {
+ AppSettings::SlideSet ss;
+ if (settings["slideSets"][i].isMember("slideDirectory"))
+ {
+ ss.slide_directory_ = resolve_path(
+ settings["slideSets"][i]["slideDirectory"].asString());
+ // start from global settings, then apply per-set overrides
+ ss.settings_ = app_settings_.global_slide_settings_;
+ load_slide_settings(settings["slideSets"][i], ss.settings_);
+ app_settings_.slide_sets_.push_back(ss);
+ }
+ else
+ {
+ std::cerr << "Warning: slide set " << i
+ << " directory not specified. Skipping" << std::endl;
+ }
+ }
+ }
+ else
+ {
+ std::cerr << "Error: slideSets not specified" << std::endl;
+ }
+ return true;
+}
+
+bool ofApp::startLogToFile()
+{
+ // TODO: Perform a check on if the log directory exists because it
+ // results in a silent fail if the directory does not exist
+ std::string log_file_name =
+ app_settings_.log_file_directory_ + get_timestamp_() + ".csv";
+ event_log_.open(log_file_name);
+ if (!event_log_.is_open())
+ {
+ std::cerr << "Failed to open log file: " << log_file_name << std::endl;
+ return false;
+ }
+ event_log_ << "dateTime,event,details\n";
+ log_stream_ = &event_log_;
+ return true;
+}
+
+void ofApp::logEvent(const std::string& event, const std::string& details)
+{
+ std::string timestamp = get_timestamp_();
+ if (log_stream_ != nullptr)
+ {
+ *log_stream_ << timestamp << ',' << event << ',' << '"' << details
+ << '"' << '\n';
+ log_stream_->flush();
+ }
+ std::cout << timestamp << ' ' << event << ' ' << details << '\n';
+}
+
+// ── Per-frame
+// ─────────────────────────────────────────────────────────────────
+
+void ofApp::update()
+{
+ if (should_exit_)
+ {
+ ofExit();
+ return;
+ }
+ updateCurrentState();
+}
+
+void ofApp::updateCurrentState()
+{
+ if (CurrentState::SlideState::kSlidePause == current_state_.slide_state_)
+ {
+ return;
+ }
+ if (current_state_.init_new_set_)
+ {
+ current_state_.slide_set_index_++;
+ if (current_state_.slide_set_index_ >=
+ (int)app_settings_.slide_sets_.size())
+ {
+ logEvent("APP_END", "reason=end_of_slide_show");
+ // TODO: consider if we want an end slide
+ should_exit_ = true;
+ return;
+ }
+ current_state_.slide_index_ =
+ -1; // gets updated in the changeSlide call
+ current_state_.slide_settings_ =
+ app_settings_.slide_sets_[current_state_.slide_set_index_]
+ .settings_;
+ current_state_.slide_dir_ =
+ app_settings_.slide_sets_[current_state_.slide_set_index_]
+ .slide_directory_;
+
+ current_state_.slide_paths_ =
+ load_slide_paths_(current_state_.slide_dir_);
+
+ if (current_state_.slide_paths_.empty())
+ {
+ logEvent(
+ "WARNING",
+ "set_index=" + std::to_string(current_state_.slide_set_index_) +
+ " reason=no_slides_found dir=" + current_state_.slide_dir_);
+ current_state_.init_new_set_ = true; // skip to next set
+ return;
+ }
+
+ // extract intro and background slides before shuffle/resize so they
+ // are not counted towards num_slides and not randomized
+ auto extract_from_set = [&](const std::string& path) -> std::string
+ {
+ if (path.empty())
+ {
+ return "";
+ }
+ std::string filename = ofFilePath::getFileName(path);
+ auto it = std::find_if(
+ current_state_.slide_paths_.begin(),
+ current_state_.slide_paths_.end(),
+ [&filename](const std::string& p)
+ { return ofFilePath::getFileName(p) == filename; });
+ if (it != current_state_.slide_paths_.end())
+ {
+ std::string extracted = *it;
+ current_state_.slide_paths_.erase(it);
+ return extracted;
+ }
+ return path; // outside the set directory — use the path directly
+ };
+
+ std::string intro_path = extract_from_set(
+ current_state_.slide_settings_.slide_set_intro_slide_);
+ extract_from_set(current_state_.slide_settings_.background_);
+
+ if (current_state_.slide_settings_.slide_order_randomization_)
+ {
+ std::shuffle(current_state_.slide_paths_.begin(),
+ current_state_.slide_paths_.end(),
+ std::mt19937{std::random_device{}()});
+ }
+ int num_slides =
+ std::min(current_state_.slide_settings_.max_slides_per_set_,
+ (int)current_state_.slide_paths_.size());
+ current_state_.slide_paths_.resize(num_slides);
+
+ if (!intro_path.empty())
+ {
+ current_state_.slide_paths_.insert(
+ current_state_.slide_paths_.begin(), intro_path);
+ }
+
+ if (!current_state_.slide_settings_.background_.empty())
+ {
+ load_background_image_(current_state_.slide_settings_.background_);
+ }
+ else
+ {
+ background_image_.clear();
+ }
+ current_state_.init_new_set_ = false;
+ std::string slide_list;
+ for (const auto& path : current_state_.slide_paths_)
+ {
+ slide_list += path + "|";
+ }
+ logEvent(
+ "SLIDE_SET_INIT",
+ "set_index=" + std::to_string(current_state_.slide_set_index_) +
+ " intro_slide=" + intro_path + " background=" +
+ current_state_.slide_settings_.background_ + " slide_count=" +
+ std::to_string(current_state_.slide_paths_.size()) +
+ " slides=" + slide_list);
+ // use existing machinery to advance to the next slide
+ changeSlide(1);
+ }
+
+ // SlideState management
+ if (CurrentState::SlideState::kSlideOn == current_state_.slide_state_)
+ {
+ if (current_state_.state_times_.on_time_ != 0)
+ {
+ // if on time is set to 0, only key strokes can change
+ // slides
+ if ((float)get_time_msec_() -
+ (float)current_state_.phase_start_msec_ >
+ current_state_.state_times_.on_time_)
+ {
+ current_state_.slide_state_ =
+ CurrentState::SlideState::kSlideOff;
+ current_state_.phase_start_msec_ = get_time_msec_();
+ logEvent(
+ "SLIDE_OFF",
+ "set_index=" +
+ std::to_string(current_state_.slide_set_index_) +
+ " slide_index=" +
+ std::to_string(current_state_.slide_index_) +
+ " OFF_TIME=" +
+ std::to_string(current_state_.state_times_.off_time_));
+ }
+ }
+ }
+ if (CurrentState::SlideState::kSlideOff == current_state_.slide_state_)
+ {
+ if (current_state_.slide_index_ == 0)
+ {
+ // increment without wait if this is an intro slide
+ // no background for intro slide
+ changeSlide(1);
+ }
+ else
+ {
+ if ((float)get_time_msec_() -
+ (float)current_state_.phase_start_msec_ >
+ current_state_.state_times_.off_time_)
+ {
+ changeSlide(1);
+ }
+ }
+ }
+}
+
+void ofApp::changeSlide(int delta)
+{
+ current_state_.slide_index_ = current_state_.slide_index_ + delta;
+ if (current_state_.slide_index_ < 0)
+ {
+ // TODO: if we press B enough times, we dont cross over to the previous
+ // set, we stay at the beginning of the current set
+ current_state_.slide_index_ = 0;
+ }
+ float on_time_min = current_state_.slide_settings_.slide_on_time_min_msec_;
+ float on_time_max = current_state_.slide_settings_.slide_on_time_max_msec_;
+ float off_time_min =
+ current_state_.slide_settings_.slide_off_time_min_msec_;
+ float off_time_max =
+ current_state_.slide_settings_.slide_off_time_max_msec_;
+ if (current_state_.slide_index_ == 0)
+ {
+ // if first slide, use the intro slide values
+ // NOTE: There is no OFF time for intro slides
+ on_time_min =
+ current_state_.slide_settings_.slide_set_intro_slide_time_min_msec_;
+ on_time_max =
+ current_state_.slide_settings_.slide_set_intro_slide_time_max_msec_;
+ }
+ if (on_time_min == on_time_max)
+ {
+ current_state_.state_times_.on_time_ = on_time_max;
+ }
+ else
+ {
+ std::mt19937 rng{std::random_device{}()};
+ std::uniform_int_distribution dist((int)on_time_min,
+ (int)on_time_max);
+ current_state_.state_times_.on_time_ = (float)dist(rng);
+ }
+ if (current_state_.slide_index_ == 0)
+ {
+ // NOTE: intro slide has no off time
+ current_state_.state_times_.off_time_ = 0;
+ }
+ else
+ {
+ if (off_time_min == off_time_max)
+ {
+ current_state_.state_times_.off_time_ = off_time_max;
+ }
+ else
+ {
+ std::mt19937 rng{std::random_device{}()};
+ std::uniform_int_distribution dist((int)off_time_min,
+ (int)off_time_max);
+ current_state_.state_times_.off_time_ = (float)dist(rng);
+ }
+ }
+ current_state_.phase_start_msec_ = get_time_msec_();
+ if (current_state_.slide_index_ >= (int)current_state_.slide_paths_.size())
+ {
+ current_state_.init_new_set_ = true;
+ }
+ else
+ {
+ current_state_.slide_state_ = CurrentState::SlideState::kSlideOn;
+ load_slide_image_(
+ current_state_.slide_paths_[current_state_.slide_index_]);
+ logEvent(
+ "SLIDE_ON",
+ "set_index=" + std::to_string(current_state_.slide_set_index_) +
+ " slide_index=" + std::to_string(current_state_.slide_index_) +
+ " path=" +
+ current_state_.slide_paths_[current_state_.slide_index_] +
+ " ON_TIME=" +
+ std::to_string(current_state_.state_times_.on_time_));
+ }
+}
+
+// ── Rendering
+// ─────────────────────────────────────────────────────────────────
+
+void ofApp::draw()
+{
+ if (CurrentState::SlideState::kSlideOff == current_state_.slide_state_)
+ {
+ drawImageFitted(background_image_);
+ }
+ else
+ {
+ drawImageFitted(current_slide_image_);
+ }
+}
+
+void ofApp::drawImageFitted(const ofImage& img)
+{
+ if (!img.isAllocated())
+ {
+ ofBackground(0);
+ return;
+ }
+ float scale = std::min((float)ofGetWidth() / img.getWidth(),
+ (float)ofGetHeight() / img.getHeight());
+ float draw_w = img.getWidth() * scale;
+ float draw_h = img.getHeight() * scale;
+ float x = ((float)ofGetWidth() - draw_w) / 2.0f;
+ float y = ((float)ofGetHeight() - draw_h) / 2.0f;
+ ofBackground(0);
+ img.draw(x, y, draw_w, draw_h);
+}
+
+// ── Input
+// ─────────────────────────────────────────────────────────────────────
+
+void ofApp::keyPressed(int key)
+{
+ // TODO: Time since phase change should be calculate for boath ON and OFF
+ // Modifier keys (Shift, Ctrl, etc.) produce large keycodes outside the
+ // printable ASCII range — skip them to avoid spurious log entries.
+ if (key > 127)
+ {
+ return;
+ }
+ const char kKeyChar = static_cast(toupper(key));
+ logEvent("KEY_PRESS", std::string("key=") + kKeyChar);
+ if (app_settings_.keyboard_controls_.next_slide_ == kKeyChar)
+ {
+ changeSlide(1);
+ }
+ if (app_settings_.keyboard_controls_.previous_slide_ == kKeyChar)
+ {
+ changeSlide(-1);
+ }
+ if (app_settings_.keyboard_controls_.restart_slide_set_ == kKeyChar)
+ {
+ changeSlide((-1 * current_state_.slide_index_));
+ }
+ if (app_settings_.keyboard_controls_.restart_slide_show_ == kKeyChar)
+ {
+ current_state_.slide_set_index_ = -1;
+ current_state_.init_new_set_ = true;
+ }
+ if (app_settings_.keyboard_controls_.pause_slide_show_toggle_ == kKeyChar)
+ {
+ if (current_state_.slide_state_ !=
+ CurrentState::SlideState::kSlidePause)
+ {
+ current_state_.slide_state_before_pause_ =
+ current_state_.slide_state_;
+ current_state_.slide_state_ = CurrentState::SlideState::kSlidePause;
+ current_state_.time_since_phase_start_on_pause_ =
+ (float)get_time_msec_() -
+ (float)current_state_.phase_start_msec_;
+ logEvent(
+ "PAUSE",
+ "set_index=" + std::to_string(current_state_.slide_set_index_) +
+ " slide_index=" +
+ std::to_string(current_state_.slide_index_));
+ }
+ else
+ {
+ current_state_.slide_state_ =
+ current_state_.slide_state_before_pause_;
+ current_state_.phase_start_msec_ =
+ get_time_msec_() -
+ (uint64_t)current_state_.time_since_phase_start_on_pause_;
+ logEvent(
+ "RESUME",
+ "set_index=" + std::to_string(current_state_.slide_set_index_) +
+ " slide_index=" +
+ std::to_string(current_state_.slide_index_));
+ }
+ }
+}
+
+void ofApp::keyReleased(int key)
+{
+}
+
+void ofApp::mouseMoved(int x, int y)
+{
+}
+
+void ofApp::mouseDragged(int x, int y, int button)
+{
+}
+
+void ofApp::mousePressed(int x, int y, int button)
+{
+}
+
+void ofApp::mouseReleased(int x, int y, int button)
+{
+}
+
+void ofApp::mouseEntered(int x, int y)
+{
+}
+
+void ofApp::mouseExited(int x, int y)
+{
+}
+
+void ofApp::windowResized(int w, int h)
+{
+}
+
+void ofApp::dragEvent(ofDragInfo dragInfo)
+{
+}
+
+void ofApp::gotMessage(ofMessage msg)
+{
+}
diff --git a/SlidePlayer/src/ofApp.h b/SlidePlayer/src/ofApp.h
new file mode 100644
index 0000000..659294b
--- /dev/null
+++ b/SlidePlayer/src/ofApp.h
@@ -0,0 +1,317 @@
+#pragma once
+
+#include
+#include
+
+#include "ofMain.h"
+
+namespace Json
+{
+class Value;
+}
+
+/// @brief Main application class for the EmotiBit slide player.
+///
+/// Manages loading settings, displaying timed sequences of image slide sets,
+/// logging events to a CSV file, and handling keyboard input.
+class ofApp : public ofBaseApp
+{
+ public:
+ // ── Data types
+ // ────────────────────────────────────────────────────────────
+
+ /// @brief All settings loaded from the JSON settings file.
+ typedef struct AppSettings
+ {
+ /// @brief Directory where the CSV log file will be written.
+ std::string log_file_directory_ = "";
+ // TODO: Need to implement the full screen and start paused
+ // implementation
+ /// @brief Whether the app starts in full-screen mode.
+ bool start_full_screen_ = true;
+ /// @brief Whether the slide show starts paused.
+ bool start_paused_ = true;
+ // TODO: implement load_settings and set_log_directory
+
+ /// @brief Keyboard shortcut bindings.
+ typedef struct KeyboardControls
+ {
+ /// @brief Key to toggle full-screen mode.
+ char toggle_full_screen_ = 'F';
+ /// @brief Key to advance to the next slide.
+ char next_slide_ = 'N';
+ /// @brief Key to go back to the previous slide.
+ char previous_slide_ = 'B';
+ /// @brief Key to toggle pause/resume.
+ char pause_slide_show_toggle_ = 'P';
+ /// @brief Key to restart the entire slide show from the beginning.
+ char restart_slide_show_ = 'R';
+ /// @brief Key to restart the current slide set from its first
+ /// slide.
+ char restart_slide_set_ = 'T';
+ /// @brief Key to reload the settings file.
+ char load_settings_file_ = 'S';
+ /// @brief Key to set the log file directory at runtime.
+ char set_log_file_directory_ = 'L';
+ } KeyboardControls;
+
+ /// @brief Active keyboard control bindings.
+ KeyboardControls keyboard_controls_;
+
+ /// @brief Display and timing settings for a slide set.
+ typedef struct SlideSettisgs
+ {
+ /// @brief Path to the background image shown during slide-off
+ /// intervals.
+ std::string background_ = "";
+ /// @brief Path to the intro slide shown at the start of the set.
+ std::string slide_set_intro_slide_ = "";
+ /// @brief Whether to pause automatically on the intro slide.
+ bool pause_on_set_intro_slide_ = true;
+ /// @brief Lower bound (ms) of the random display time for the intro
+ /// slide. If equal to max, the value is used directly.
+ float slide_set_intro_slide_time_min_msec_ = 0;
+ /// @brief Upper bound (ms) of the random display time for the intro
+ /// slide. If equal to min, the value is used directly.
+ float slide_set_intro_slide_time_max_msec_ = 0;
+ /// @brief Whether to randomize slide order within the set.
+ bool slide_order_randomization_ = true;
+ /// @brief Maximum number of slides to show per set.
+ int max_slides_per_set_ = 5;
+ /// @brief Lower bound (ms) of the random on-time per slide.
+ /// If equal to max, the value is used directly. If both are 0,
+ /// only key presses advance the slide.
+ float slide_on_time_min_msec_ = 0;
+ /// @brief Upper bound (ms) of the random on-time per slide.
+ /// If equal to min, the value is used directly. If both are 0,
+ /// only key presses advance the slide.
+ float slide_on_time_max_msec_ = 0;
+ /// @brief Lower bound (ms) of the random off-time between slides.
+ /// If equal to max, the value is used directly.
+ float slide_off_time_min_msec_ = 0;
+ /// @brief Upper bound (ms) of the random off-time between slides.
+ /// If equal to min, the value is used directly.
+ float slide_off_time_max_msec_ = 0;
+ } SlideSettings;
+
+ /// @brief Global slide settings used as defaults for all sets.
+ SlideSettisgs global_slide_settings_;
+
+ /// @brief A single slide set — a directory of images and its settings.
+ typedef struct SlideSet
+ {
+ /// @brief Path to the directory containing the slide images.
+ std::string slide_directory_ = "";
+ /// @brief Per-set settings, inheriting from global with optional
+ /// overrides.
+ SlideSettings settings_;
+ } SlideSet;
+
+ /// @brief Ordered list of slide sets to display during the session.
+ std::vector slide_sets_;
+ } AppSettings;
+
+ /// @brief Runtime state of the slide show.
+ typedef struct CurrentState
+ {
+ /// @brief Whether the current set needs to be initialised on the next
+ /// update.
+ bool init_new_set_ = true;
+ /// @brief Index of the active slide set. -1 = uninitialized.
+ int slide_set_index_ = -1;
+ /// @brief Index of the active slide within the current set.
+ int slide_index_ = 0;
+ /// @brief Path to the active slide set directory.
+ std::string slide_dir_;
+ /// @brief Ordered list of image paths for the current set.
+ std::vector slide_paths_;
+ /// @brief Active display/timing settings for the current set.
+ AppSettings::SlideSettings slide_settings_;
+ /// @brief Timestamp (ms) when the current ON or OFF phase started.
+ uint64_t phase_start_msec_ = 0;
+
+ /// @brief Phase states for the slide show state machine.
+ enum class SlideState
+ {
+ kSlideOn, ///< Slide image is visible.
+ kSlideOff, ///< Screen is blank between slides.
+ kSlidePause, ///< Show is paused by the user.
+ kSlideIntro ///< Intro slide is visible.
+ };
+
+ /// @brief Holds the randomly chosen on and off durations for the
+ /// current slide, sampled once per slide change from the min/max
+ /// ranges in SlideSettings.
+ typedef struct StateTimes
+ {
+ /// @brief Randomly chosen duration (ms) the slide stays visible.
+ float on_time_ = 0;
+ /// @brief Randomly chosen duration (ms) the screen stays blank
+ /// after the slide goes off.
+ float off_time_ = 0;
+ } StateTimes;
+ /// @brief Active on/off durations for the current slide.
+ StateTimes state_times_;
+ /// @brief Current phase state.
+ SlideState slide_state_ = SlideState::kSlideOn;
+ /// @brief State that was active before the show was paused.
+ SlideState slide_state_before_pause_ = SlideState::kSlideOn;
+ /// @brief Elapsed time in the current phase at the moment pause was
+ /// triggered (ms).
+ float time_since_phase_start_on_pause_ = 0;
+ } CurrentState;
+
+ // ── Member variables
+ // ──────────────────────────────────────────────────────
+
+ /// @brief Settings loaded from the JSON file.
+ AppSettings app_settings_;
+ /// @brief Live runtime state of the slide show.
+ CurrentState current_state_;
+ /// @brief When true, @c update() will call @c ofExit().
+ bool should_exit_ = false;
+ /// @brief File name of the JSON settings file.
+ std::string settings_file_name_ = "emotibitSlidePlayerSettings.json";
+ /// @brief Compact single-line JSON snapshot of loaded settings, written to
+ /// the log on startup.
+ std::string settings_json_;
+
+ /// @brief Returns the current time in milliseconds. Injectable for testing.
+ std::function get_time_msec_ = []()
+ { return static_cast(ofGetElapsedTimeMillis()); };
+
+ /// @brief Returns a formatted timestamp string. Injectable for testing.
+ std::function get_timestamp_ = []()
+ { return ofGetTimestampString(); };
+
+ /// @brief Loads and returns sorted image paths from a directory. Injectable
+ /// for testing.
+ std::function(const std::string&)>
+ load_slide_paths_ = [](const std::string& dir)
+ {
+ if (!ofDirectory::doesDirectoryExist(dir))
+ {
+ std::cerr << "Error: slide directory not found: " << dir
+ << std::endl;
+ return std::vector{};
+ }
+ ofDirectory d(dir);
+ // TODO: consider if other file extensions should be allowed when
+ // listing the files
+ d.allowExt("jpg");
+ d.allowExt("jpeg");
+ d.allowExt("png");
+ d.allowExt("bmp");
+ d.listDir();
+ d.sort();
+ std::vector paths;
+ for (int i = 0; i < (int)d.size(); i++)
+ {
+ paths.push_back(d.getPath(i));
+ }
+ return paths;
+ };
+
+ /// @brief Loads an image into @c current_slide_image_. Injectable for
+ /// testing.
+ std::function load_slide_image_ =
+ [this](const std::string& path) { current_slide_image_.load(path); };
+
+ /// @brief Loads an image into @c background_image_. Injectable for testing.
+ std::function load_background_image_ =
+ [this](const std::string& path) { background_image_.load(path); };
+
+ /// @brief Currently displayed slide image.
+ ofImage current_slide_image_;
+ /// @brief Background image shown during slide-off intervals.
+ ofImage background_image_;
+ /// @brief File stream for the CSV event log.
+ std::ofstream event_log_;
+ /// @brief Pointer to the active log output stream. Points to @c event_log_
+ /// after file open. Injectable for testing.
+ std::ostream* log_stream_ = nullptr;
+
+ // ── Setup
+ // ─────────────────────────────────────────────────────────────────
+
+ /// @brief Ensures the settings file exists in ~/Documents/EmotiBit/.
+ /// Copies it from the app bundle Resources if not present, then updates
+ /// settings_file_name_ to the absolute path.
+ void ensureSettingsFile();
+
+ /// @brief openFrameworks setup callback. Loads settings and opens the log
+ /// file.
+ void setup();
+
+ /// @brief Reads the JSON settings file from disk and calls parseSettings().
+ /// @return True on success, false if the file is missing or unparseable.
+ bool loadAppSettings();
+
+ /// @brief Parses a JSON value into @c app_settings_.
+ /// @param settings Root JSON object from the settings file.
+ /// @return Always returns true; individual missing keys are reported to
+ /// stderr.
+ bool parseSettings(const Json::Value& settings);
+
+ /// @brief Opens the CSV log file and writes the header row.
+ /// @return True if the file was opened successfully.
+ bool startLogToFile();
+
+ /// @brief Writes a single event row to the CSV log and echoes it to stdout.
+ /// @param event Event name (e.g. "SLIDE_ON", "KEY_PRESS").
+ /// @param details Space-separated key=value pairs describing the event.
+ void logEvent(const std::string& event, const std::string& details);
+
+ // ── Per-frame
+ // ─────────────────────────────────────────────────────────────
+
+ /// @brief openFrameworks per-frame update callback.
+ void update();
+
+ /// @brief Drives the slide show state machine: initialises sets, manages
+ /// ON/OFF transitions, and advances slides based on timing.
+ void updateCurrentState();
+
+ /// @brief Advances or retreats the current slide index by @p delta.
+ /// @param delta Positive to go forward, negative to go backward.
+ void changeSlide(int delta);
+
+ // ── Rendering
+ // ─────────────────────────────────────────────────────────────
+
+ /// @brief openFrameworks per-frame draw callback.
+ void draw();
+
+ /// @brief Draws @p img centred and aspect-ratio-fitted to the window.
+ /// Fills the window with black if the image is not allocated.
+ /// @param img Image to draw.
+ void drawImageFitted(const ofImage& img);
+
+ // ── Input
+ // ─────────────────────────────────────────────────────────────────
+
+ /// @brief Handles key-down events for slide navigation, pause, and restart.
+ /// @param key ASCII key code. Modifier keys (>127) are ignored.
+ void keyPressed(int key);
+
+ /// @brief openFrameworks key-release callback (unused).
+ void keyReleased(int key);
+ /// @brief openFrameworks mouse-move callback (unused).
+ void mouseMoved(int x, int y);
+ /// @brief openFrameworks mouse-drag callback (unused).
+ void mouseDragged(int x, int y, int button);
+ /// @brief openFrameworks mouse-press callback (unused).
+ void mousePressed(int x, int y, int button);
+ /// @brief openFrameworks mouse-release callback (unused).
+ void mouseReleased(int x, int y, int button);
+ /// @brief openFrameworks mouse-enter callback (unused).
+ void mouseEntered(int x, int y);
+ /// @brief openFrameworks mouse-exit callback (unused).
+ void mouseExited(int x, int y);
+ /// @brief openFrameworks window-resize callback (unused).
+ void windowResized(int w, int h);
+ /// @brief openFrameworks drag-and-drop callback (unused).
+ void dragEvent(ofDragInfo dragInfo);
+ /// @brief openFrameworks message callback (unused).
+ void gotMessage(ofMessage msg);
+};
diff --git a/SlidePlayer/tests/test_parseSettings.cpp b/SlidePlayer/tests/test_parseSettings.cpp
new file mode 100644
index 0000000..ee94502
--- /dev/null
+++ b/SlidePlayer/tests/test_parseSettings.cpp
@@ -0,0 +1,99 @@
+#include
+
+#include "json/json.h"
+#include "ofApp.h"
+
+TEST_CASE("global slide settings are loaded", "[parseSettings]")
+{
+ Json::Value root;
+ root["globalSlideSettings"]["background"] = "./bg.jpg";
+ root["globalSlideSettings"]["maxSlidesPerSet"] = 3;
+ root["globalSlideSettings"]["slideOrderRandomization"] = false;
+ root["globalSlideSettings"]["slideOnTimeMin_msec"] = 1000.0f;
+ root["globalSlideSettings"]["slideOnTimeMax_msec"] = 2000.0f;
+
+ ofApp app;
+ app.parseSettings(root);
+
+ REQUIRE(app.app_settings_.global_slide_settings_.background_ == "./bg.jpg");
+ REQUIRE(app.app_settings_.global_slide_settings_.max_slides_per_set_ == 3);
+ REQUIRE(
+ app.app_settings_.global_slide_settings_.slide_order_randomization_ ==
+ false);
+ REQUIRE(app.app_settings_.global_slide_settings_.slide_on_time_min_msec_ ==
+ 1000.0f);
+ REQUIRE(app.app_settings_.global_slide_settings_.slide_on_time_max_msec_ ==
+ 2000.0f);
+}
+
+TEST_CASE("per-set settings override global settings", "[parseSettings]")
+{
+ Json::Value root;
+ root["globalSlideSettings"]["maxSlidesPerSet"] = 5;
+ root["globalSlideSettings"]["slideOrderRandomization"] = true;
+ root["slideSets"][0]["slideDirectory"] = "./set01/";
+ root["slideSets"][0]["maxSlidesPerSet"] = 2; // override
+
+ ofApp app;
+ app.parseSettings(root);
+
+ REQUIRE(app.app_settings_.slide_sets_[0].settings_.max_slides_per_set_ ==
+ 2);
+ // slideOrderRandomization was not overridden — should inherit global value
+ REQUIRE(
+ app.app_settings_.slide_sets_[0].settings_.slide_order_randomization_ ==
+ true);
+}
+
+TEST_CASE("per-set inherits global when not overridden", "[parseSettings]")
+{
+ Json::Value root;
+ root["globalSlideSettings"]["maxSlidesPerSet"] = 5;
+ root["slideSets"][0]["slideDirectory"] = "./set01/";
+
+ ofApp app;
+ app.parseSettings(root);
+
+ REQUIRE(app.app_settings_.slide_sets_[0].settings_.max_slides_per_set_ ==
+ 5);
+}
+
+TEST_CASE("slide set without slideDirectory is skipped", "[parseSettings]")
+{
+ Json::Value root;
+ root["globalSlideSettings"]["maxSlidesPerSet"] = 5;
+ root["slideSets"][0]["maxSlidesPerSet"] = 2; // no slideDirectory
+
+ ofApp app;
+ app.parseSettings(root);
+
+ REQUIRE(app.app_settings_.slide_sets_.empty());
+}
+
+TEST_CASE("app settings are loaded", "[parseSettings]")
+{
+ Json::Value root;
+ root["appSettings"]["startFullScreen"] = false;
+ root["appSettings"]["startPaused"] = false;
+ root["appSettings"]["logFileDirectory"] = "~/Documents/logs/";
+
+ ofApp app;
+ app.parseSettings(root);
+
+ REQUIRE(app.app_settings_.start_full_screen_ == false);
+ REQUIRE(app.app_settings_.start_paused_ == false);
+ REQUIRE(app.app_settings_.log_file_directory_ == "~/Documents/logs/");
+}
+
+TEST_CASE("keyboard controls are loaded", "[parseSettings]")
+{
+ Json::Value root;
+ root["appSettings"]["keyboardControls"]["toggleFullScreen"] = "G";
+ root["appSettings"]["keyboardControls"]["nextSlide"] = "M";
+
+ ofApp app;
+ app.parseSettings(root);
+
+ REQUIRE(app.app_settings_.keyboard_controls_.toggle_full_screen_ == 'G');
+ REQUIRE(app.app_settings_.keyboard_controls_.next_slide_ == 'M');
+}
diff --git a/SlidePlayer/tests/test_updateCurrentState.cpp b/SlidePlayer/tests/test_updateCurrentState.cpp
new file mode 100644
index 0000000..cd15cba
--- /dev/null
+++ b/SlidePlayer/tests/test_updateCurrentState.cpp
@@ -0,0 +1,268 @@
+#include
+#include
+
+#include "ofApp.h"
+
+// ── Helpers
+// ───────────────────────────────────────────────────────────────
+
+static ofApp makeApp(std::vector slide_paths,
+ uint64_t& fake_time,
+ float slide_on_time_max_msec = 1000.0f,
+ float slide_off_time_max_msec = 500.0f,
+ std::ostream* log_stream = nullptr)
+{
+ ofApp app;
+ app.log_stream_ = log_stream;
+
+ // inject no-op image loaders
+ app.load_slide_image_ = [](const std::string&) {};
+ app.load_background_image_ = [](const std::string&) {};
+
+ // inject fake path loader
+ app.load_slide_paths_ = [slide_paths](const std::string&)
+ { return slide_paths; };
+
+ // inject controllable clock and fixed timestamp
+ app.get_time_msec_ = [&fake_time]() { return fake_time; };
+ app.get_timestamp_ = []() { return std::string("2026-01-01T00:00:00"); };
+
+ // one slide set with the given timing
+ ofApp::AppSettings::SlideSet ss;
+ ss.slide_directory_ = "./fake/";
+ ss.settings_.slide_on_time_max_msec_ = slide_on_time_max_msec;
+ ss.settings_.slide_set_intro_slide_time_max_msec_ = slide_on_time_max_msec;
+ ss.settings_.slide_off_time_max_msec_ = slide_off_time_max_msec;
+ ss.settings_.slide_order_randomization_ = false;
+ ss.settings_.max_slides_per_set_ = (int)slide_paths.size();
+ app.app_settings_.slide_sets_.push_back(ss);
+
+ return app;
+}
+
+// ── Tests: set initialisation
+// ─────────────────────────────────────────────────────
+
+TEST_CASE("slide set is initialised on first update", "[updateCurrentState]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"a.jpg", "b.jpg", "c.jpg"}, fake_time);
+
+ app.updateCurrentState();
+
+ REQUIRE(app.current_state_.slide_set_index_ == 0);
+ REQUIRE(app.current_state_.slide_index_ == 0);
+ REQUIRE(app.current_state_.slide_paths_.size() == 3);
+ REQUIRE_FALSE(app.current_state_.init_new_set_);
+}
+
+TEST_CASE("slide state is ON after set init", "[updateCurrentState]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"a.jpg", "b.jpg"}, fake_time);
+
+ app.updateCurrentState();
+
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlideOn);
+}
+
+// ── Tests: ON → OFF transition
+// ────────────────────────────────────────────────
+
+TEST_CASE("intro slide advances immediately when ON time expires",
+ "[updateCurrentState]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"intro.jpg", "a.jpg", "b.jpg"}, fake_time, /*on=*/1000.0f);
+
+ app.updateCurrentState(); // init, t=0, index=0 (intro), ON
+
+ fake_time = 1500;
+ app.updateCurrentState(); // intro expires → skips OFF → index=1, ON
+
+ REQUIRE(app.current_state_.slide_index_ == 1);
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlideOn);
+}
+
+TEST_CASE("slide transitions to OFF after max_on_time", "[updateCurrentState]")
+{
+ uint64_t fake_time = 0;
+ ofApp app =
+ makeApp({"intro.jpg", "a.jpg", "b.jpg"}, fake_time, /*on=*/1000.0f);
+
+ app.updateCurrentState(); // init, t=0, index=0 (intro), ON
+
+ fake_time = 1500;
+ app.updateCurrentState(); // intro expires → index=1, ON, phase=1500
+
+ fake_time = 3000;
+ app.updateCurrentState(); // index=1: 3000-1500=1500 > 1000 → OFF
+
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlideOff);
+}
+
+TEST_CASE("slide stays ON before max_on_time elapses", "[updateCurrentState]")
+{
+ uint64_t fake_time = 0;
+ ofApp app =
+ makeApp({"intro.jpg", "a.jpg", "b.jpg"}, fake_time, /*on=*/1000.0f);
+
+ app.updateCurrentState(); // init, index=0 (intro), ON
+
+ fake_time = 1500;
+ app.updateCurrentState(); // intro expires → index=1, ON, phase=1500
+
+ fake_time = 2000;
+ app.updateCurrentState(); // 2000-1500=500 < 1000 → stays ON
+
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlideOn);
+}
+
+TEST_CASE("slide stays ON forever when max_on_time is 0", "[updateCurrentState]")
+{
+ uint64_t fake_time = 0;
+ ofApp app =
+ makeApp({"intro.jpg", "a.jpg", "b.jpg"}, fake_time, /*on=*/0.0f);
+
+ app.updateCurrentState(); // init, index=0 (intro), ON — intro time also 0
+
+ fake_time = 99999;
+ app.updateCurrentState(); // stays ON forever
+
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlideOn);
+}
+
+// ── Tests: OFF → next slide
+// ───────────────────────────────────────────────────
+
+TEST_CASE("slide advances after max_off_time", "[updateCurrentState]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"intro.jpg", "a.jpg", "b.jpg"}, fake_time,
+ /*on=*/1000.0f, /*off=*/500.0f);
+
+ app.updateCurrentState(); // init, t=0, index=0 (intro), ON
+
+ fake_time = 1500;
+ app.updateCurrentState(); // intro expires → index=1, ON, phase=1500
+
+ fake_time = 2600;
+ app.updateCurrentState(); // index=1 ON: 2600-1500=1100 > 1000 → OFF, phase=2600
+
+ fake_time = 3200;
+ app.updateCurrentState(); // OFF: 3200-2600=600 > 500 → index=2, ON
+
+ REQUIRE(app.current_state_.slide_index_ == 2);
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlideOn);
+}
+
+// ── Tests: pause / resume
+// ─────────────────────────────────────────────────────
+
+TEST_CASE("pause stops state transitions", "[keyPressed]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"a.jpg", "b.jpg"}, fake_time, /*on=*/1000.0f);
+ app.load_slide_image_ = [](const std::string&) {};
+
+ app.updateCurrentState(); // init
+
+ // pause
+ app.keyPressed('P');
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlidePause);
+
+ // time passes but state must not change
+ fake_time = 9999;
+ app.updateCurrentState();
+
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlidePause);
+}
+
+TEST_CASE("resume restores previous state", "[keyPressed]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"a.jpg", "b.jpg"}, fake_time, /*on=*/1000.0f);
+
+ app.updateCurrentState(); // init, state = ON
+
+ app.keyPressed('P'); // pause
+ app.keyPressed('P'); // resume
+
+ REQUIRE(app.current_state_.slide_state_ ==
+ ofApp::CurrentState::SlideState::kSlideOn);
+}
+
+// ── Tests: manual slide navigation
+// ───────────────────────────────────────
+
+TEST_CASE("next key advances slide index", "[keyPressed]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"a.jpg", "b.jpg", "c.jpg"}, fake_time);
+
+ app.updateCurrentState(); // init
+
+ app.keyPressed('N');
+
+ REQUIRE(app.current_state_.slide_index_ == 1);
+}
+
+TEST_CASE("previous key does not go below 0", "[keyPressed]")
+{
+ uint64_t fake_time = 0;
+ ofApp app = makeApp({"a.jpg", "b.jpg"}, fake_time);
+
+ app.updateCurrentState(); // init, slide_index = 0
+
+ app.keyPressed('B');
+
+ REQUIRE(app.current_state_.slide_index_ == 0);
+}
+
+// ── Tests: log output
+// ─────────────────────────────────────────────────────────
+
+TEST_CASE("PAUSE event is written to log stream", "[logEvent]")
+{
+ uint64_t fake_time = 0;
+ std::ostringstream log;
+ ofApp app = makeApp({"a.jpg", "b.jpg"}, fake_time, 1000.0f, 500.0f, &log);
+
+ app.updateCurrentState();
+ app.keyPressed('P');
+
+ REQUIRE(log.str().find("PAUSE") != std::string::npos);
+}
+
+TEST_CASE("RESUME event is written to log stream", "[logEvent]")
+{
+ uint64_t fake_time = 0;
+ std::ostringstream log;
+ ofApp app = makeApp({"a.jpg", "b.jpg"}, fake_time, 1000.0f, 500.0f, &log);
+
+ app.updateCurrentState();
+ app.keyPressed('P'); // pause
+ app.keyPressed('P'); // resume
+
+ REQUIRE(log.str().find("RESUME") != std::string::npos);
+}
+
+TEST_CASE("SLIDE_ON event is written to log stream on advance", "[logEvent]")
+{
+ uint64_t fake_time = 0;
+ std::ostringstream log;
+ ofApp app = makeApp({"a.jpg", "b.jpg"}, fake_time, 1000.0f, 500.0f, &log);
+
+ app.updateCurrentState();
+ app.keyPressed('N');
+
+ REQUIRE(log.str().find("SLIDE_ON") != std::string::npos);
+}
diff --git a/src/ofxEmotiBitVersion.h b/src/ofxEmotiBitVersion.h
index 4a56a9f..284f7bb 100644
--- a/src/ofxEmotiBitVersion.h
+++ b/src/ofxEmotiBitVersion.h
@@ -2,8 +2,7 @@
//#include
#include "ofMain.h"
-
-const std::string ofxEmotiBitVersion = "1.14.7";
+const std::string ofxEmotiBitVersion = "1.15.0";
static const char SOFTWARE_VERSION_PREFIX = 'v';